负载均衡 Ribbon 与 Fegin 远程调用原理

2024-09-06 07:20

本文主要是介绍负载均衡 Ribbon 与 Fegin 远程调用原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、什么是负载均衡
  • 二、Ribbon 负载均衡
    • 2.1 Ribbon 使用
    • 2.2 Ribbon 实现原理 (★)
    • 2.3 Ribbon 负载均衡算法
  • 三、Feign 远程调用
    • 3.1 Feign 简述
    • 3.2 Feign 的集成
    • 3.3 Feign 实现原理 (★)


一、什么是负载均衡

《服务治理:Nacos 注册中心》 末尾提到了负载均衡,那什么是负载均衡呢?

负载均衡就是将负载(⼯作任务,访问请求)进⾏分摊到多个操作单元(服务器,组件)上进行执行
根据负载均衡发⽣位置的不同,⼀般分为: 服务端负载均衡客户端负载均衡

  • 服务端负载均衡指的是发生在服务提供者一方,比如常见的 Nginx 负载均衡。
  • 客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求。

在这里插入图片描述
注:在微服务调⽤关系中⼀般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。


二、Ribbon 负载均衡

2.1 Ribbon 使用

Ribbon 是 Spring Cloud 的⼀个组件, 它可以让我们使用一个注解就能轻松的搞定负载均衡。

1、在 RestTemplate 的生成方法上添加 @LoadBalanced 注解

@Bean
@LoadBalanced // 表示继承Ribbon进行负载均衡
public RestTemplate restTemplate() {return new RestTemplate();
}

2、修改服务调用的方法

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate RestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {log.info("接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息", productId);// 远程调⽤商品微服务,查询商品信息String url = "http://product-service/product/" + productId;log.info("服务器地址: {}", url);// 远程调⽤商品微服务,查询商品信息Product product = restTemplate.getForObject(url, Product.class);log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));// 创建订单并保存Order order = new Order();order.setUid(userId);order.setUsername("安秀岩");order.setPid(productId);order.setName(product.getName());order.setPrice(product.getPrice());order.setNumber(1);orderDao.save(order);log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));return order;}
}

在这里插入图片描述
对比以下两种方式,差异显著:

 //⾃定义规则实现随机挑选服务List<ServiceInstance> instances = discoveryClient.getInstances("product-service");int index = new Random().nextInt(instances.size());ServiceInstance instance = instances.get(index);String url = instance.getHost() + ":" + instance.getPort();log.info("从nacos中获取到的微服务地址为:" + url);简化成了以下一行// Ribbon 直接使用需要远程调用的服务名称即可
String url = "http://product-service/";

那 Ribbon 底层原理又是什么呢?为什么可以使用服务名称就能远程调用该服务呢?


2.2 Ribbon 实现原理 (★)

现假设:两个商品服务做集群,向Nacos注册的IP分别是192.168.10.111:8081192.168.10.112:8081

step1:当使用 RestTemplate 远程访问时,http://product-service/product/1 首先会将服务名称截取出来 product-service
step2:并在本地缓存列表中获取到服务的 IP 集合,即{{192.168.10.111:8081}, {192.168.10.112:8081}}
step3:根据内部配置的 负载均衡算法,从集合中选取其中一个IP地址,如:192.168.10.112:8081
step4:将原来的 url 替换成 http://192.168.10.112:8081/product/1,最终通过 RestTemplate 发起请求。


2.3 Ribbon 负载均衡算法

Ribbon 内置了多种负载均衡策略,内部负载均衡的顶级接口为 com.netflix.loadbalancer.IRule,具体的负载策略如下图所示:

在这里插入图片描述
可以通过修改配置来调整 Ribbon 的负载均衡策略,如在 order-server 项目的 application.yml 中增加如下配置:

product-service: # 调⽤的提供者的名称ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

三、Feign 远程调用

3.1 Feign 简述

为什么要使用 feign 呢?原来的调用的方式 String url = "http://product-service/product/" + productId; 是固定的字符串做拼接不够灵活,而且还存在 productId 参数校验问题等,因此 Feign 可解决这个问题。

  Feign 是 Spring Cloud 提供的⼀个声明式的伪 Http 客户端,它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。Nacos 很好的兼容了 Feign,Feign 默认集成了 Ribbon,所以在 Nacos 下使用 Fegin 默认就实现了负载均衡的效果


3.2 Feign 的集成

1、在shop-order-server项⽬的pom文件加入Fegin的依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、在启动类上添加 Fegin 的扫描注解 @EnableFeignClients,注意扫描路径(默认扫描当前包及其子包)

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 会扫描当包及其子包下贴有@FeignClient注解的接口
public class OrderServer {public static void main(String[] args) {SpringApplication.run(ProductApplication .class, args);}
}

3、在 shop-order-server 项目中新增接口 ProductFeignApi 和该接口的容错类 ProductFeignFallback

@FeignClient(name = "product-service", fallback = ProductFeignFallback.class)
// 远程调用服务名称;fallback 指定返回兜底数据的类的字节码,即服务挂起时的降级类方法
public interface ProductFeignApi {@RequestMapping("/product/{pid}")// 路径要与 ProductController 的接口保持一致Product findByPid(@PathVariable("pid") Long pid);
}
@Component // 该类的作用是返回兜底数据以防 “服务器雪崩”
public class ProductFeignFallback implements ProductFeignApi {@Overridepublic Product findByPid(Long pid) {System.out.println("返回兜底数据");return new Product();}
}

在这里插入图片描述

4、修改服务调用的方法

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate ProductFeignApi productFeignApi;@Overridepublic Order createOrderFeign(Long productId, Long userId) {// feign 调用Product product = productFeignApi.findByPid(productId);log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));// 创建订单并保存Order order = new Order();order.setUid(userId);order.setUsername("叩丁狼教育");order.setPid(productId);order.setName(product.getName());order.setPrice(product.getPrice());order.setNumber(1);orderDao.save(order);log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));return order;}
}

3.3 Feign 实现原理 (★)

Feign 实现的原理是基于动态代理和反射技术,并且内部还是使用 RestTemplate 实现的,具体详细流程如下:
在这里插入图片描述


文章参考:Java微服务商城高并发秒杀项目实战|Spring Cloud Alibaba真实项目实战+商城双11秒杀+高并发+消息+支付+分布式事物Seata

这篇关于负载均衡 Ribbon 与 Fegin 远程调用原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141376

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

java程序远程debug原理与配置全过程

《java程序远程debug原理与配置全过程》文章介绍了Java远程调试的JPDA体系,包含JVMTI监控JVM、JDWP传输调试命令、JDI提供调试接口,通过-Xdebug、-Xrunjdwp参数配... 目录背景组成模块间联系IBM对三个模块的详细介绍编程使用总结背景日常工作中,每个程序员都会遇到bu

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程