概述

官方github:https://github.com/Netflix/ribbon

Ribbon is a Inter Process Communication (remote procedure calls) library with built in software load balancers. The primary usage model involves REST calls with various serialization scheme support.

Ribbon is a client side IPC library that is battle-tested in cloud. It provides the following features Load balancing Fault tolerance Multiple protocol (HTTP, TCP, UDP) support in an asynchronous and reactive model Caching and batching Ribbon 是一个进程间通信的客户端库,并且已经在云环境下经过大量的生产测试。它提供了以下功能: 负载均衡 容错机制 支持 HTTP、TCP、UDP 等多种协议,并支持异步和响应式的调用方式 缓存与批处理

mavn配置

  1. <dependency>
  2. <groupId>com.netflix.ribbon</groupId>
  3. <artifactId>ribbon</artifactId>
  4. <version>2.2.2</version>
  5. </dependency>

Ribbon的常用配置

全局配置

  1. ribbon:
  2. ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
  3. ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
  4. OkToRetryOnAllOperations: true #对超时请求启用重试机制
  5. MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
  6. MaxAutoRetries: 1 # 切换实例后重试最大次数
  7. NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法

指定服务进行配置

与全局配置的区别就是ribbon节点挂在服务名称下面,如下是对ribbon-service调用user-service服务时的单独配置。

  1. user-service:
  2. ribbon:
  3. ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
  4. ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
  5. OkToRetryOnAllOperations: true #对超时请求启用重试机制
  6. MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
  7. MaxAutoRetries: 1 # 切换实例后重试最大次数
  8. NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法

负载均衡策略

负载均衡策略就是指当A服务调用B服务时,此时B服务有多个实例,这时A服务以何种方式来选择调用的B实例,ribbon可以选择以下几种负载均衡策略。

负载均衡策略 说明
com.netflix.loadbalancer.RandomRule 从提供服务的实例中以随机的方式
com.netflix.loadbalancer.RoundRobinRule 以线性轮询的方式,就是维护一个计数器,从提供服务的实例中按顺序选取,第一次选第一个,第二次选第二个,以此类推,到最后一个以后再从头来过
com.netflix.loadbalancer.RetryRule 在RoundRobinRule的基础上添加重试机制,即在指定的重试时间内,反复使用线性轮询策略来选择可用实例
com.netflix.loadbalancer.WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
com.netflix.loadbalancer.BestAvailableRule 选择并发较小的实例
com.netflix.loadbalancer.AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
com.netflix.loadbalancer.ZoneAwareLoadBalancer 采用双重过滤,同时过滤不是同一区域的实例和故障实例,选择并发较小的实例
策略名 策略描述 实现说明
RandomRule 随机选择一个 server 在 index 上随机,选择 index 对应位置的 Server
RoundRobinRule 轮询选择 server 轮询 index,选择 index 对应位置的 server
ZoneAvoidanceRule 复合判断 server 所在区域的性能和 server 的可用性选择 server 使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 来判断是否选择某个 server。ZoneAvoidancePredicate 判断判定一个 zone 的运行性能是否可用,剔除不可用的 zone(的所有 server);AvailabilityPredicate 用于过滤掉连接数过多的 server。
BestAvailableRule 选择一个最小并发请求的 server 逐个考察 server,如果 server 被 tripped 了则忽略,在选择其中activeRequestsCount 最小的 server
AvailabilityFilteringRule 过滤掉那些因为一直连接失败的被标记为 circuit tripped 的后端 server,并过滤掉那些高并发的的后端 server(activeConnections 超过配置的阈值) 使用一个 AvailabilityPredicate 来包含过滤 server 的逻辑,其实就就是检查 status 里记录的各个 server 的运行状态
WeightedResponseTimeRule 根据 server 的响应时间分配一个 weight,响应时间越长,weight 越小,被选中的可能性越低 一个后台线程定期的从 status 里面读取评价响应时间,为每个 server 计算一个 weight。weight 的计算也比较简单,responseTime 减去每个 server 自己平均的 responseTime 是 server 的权重。当刚开始运行,没有形成 status 时,使用 RoundRobinRule 策略选择 server。
RetryRule 对选定的负载均衡策略机上重试机制 在一个配置时间段内当选择 server 不成功,则一直尝试使用 subRule 的方式选择一个可用的 server

默认情况下,Ribbon 采用 ZoneAvoidanceRule 规则。因为大多数公司是单机房,所以一般只有一个 zone,而 ZoneAvoidanceRule 在仅有一个 zone 的情况下,会退化成轮询的选择方式,所以会和 RoundRobinRule 规则类似。

创建user-service

图片.png

在pom.xml 添加相关依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-web</artifactId>
  9. </dependency>
  10. </dependencies>

application.yaml 配置文件

  1. server:
  2. port: 8201
  3. spring:
  4. application:
  5. name: user-service
  6. eureka:
  7. client:
  8. register-with-eureka: true
  9. fetch-registry: true
  10. service-url:
  11. defaultZone: http://localhost:8001/eureka/

创建
图片.png

一个服务启动多个实例图片.png查看eureka注册中心

图片.png

调用接口进行测试:http://localhost:8301/user/1

使用nacos

  1. <dependencies>
  2. <!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- 引入 Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心,并实现对其的自动配置 -->
  8. <dependency>
  9. <groupId>com.alibaba.cloud</groupId>
  10. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  11. </dependency>
  12. </dependencies>

没有主动引入 spring-cloud-netflix-ribbon 依赖,因为 spring-cloud-starter-alibaba-nacos-discovery 默认引入了它

application.yaml

  1. server:
  2. port: 18808
  3. spring:
  4. application:
  5. name: ribbon-echo-provider # 应用名
  6. cloud:
  7. nacos:
  8. # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
  9. discovery:
  10. server-addr: 127.0.0.1:8848 # Nacos 服务器地址

创建RibbonEchoController

  1. @RestController
  2. public class RibbonEchoController {
  3. @Value("${server.port}")
  4. private Integer serverPort;
  5. @GetMapping("/echo")
  6. public String echo(String s) throws InterruptedException {
  7. // 模拟执行 100ms 时长。方便后续我们测试请求超时
  8. Thread.sleep(100L);
  9. return serverPort+" [echo]:" + s;
  10. }
  11. }

http://127.0.0.1:18808/echo?s=hello

消费者

@LoadBalanced 注解,声明 RestTemplate Bean 被配置使用 Spring Cloud LoadBalancerClient(负载均衡客户端),实现在请求目标服务时,能够进行负载均衡。

  1. @Configuration
  2. public class RestTemplateConfig {
  3. @Bean(name = "restTemplate")
  4. public RestTemplate restTemplate(){
  5. return new RestTemplate();
  6. }
  7. @Bean(name = "loadBalancedRestTemplate")
  8. @LoadBalanced
  9. public RestTemplate loadBalancedRestTemplate(){
  10. return new RestTemplate();
  11. }
  12. }@Configuration
  13. public class RestTemplateConfig {
  14. @Bean
  15. @LoadBalanced
  16. public RestTemplate restTemplate(){
  17. return new RestTemplate();
  18. }
  19. }

消费端配置信息application.yaml

  1. server:
  2. port: 18080 # 服务器端口。默认为 8080
  3. spring:
  4. application:
  5. name: ribbon-echo-consumer # Spring 应用名
  6. cloud:
  7. nacos:
  8. # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
  9. discovery:
  10. server-addr: 127.0.0.1:8848 # Nacos 服务器地址
  11. service-url:
  12. ribbon-echo-service: ribbon-echo-provider

controller

  1. @RestController
  2. public class EchoLoadBalancerController {
  3. @Value("${service-url.ribbon-echo-service}")
  4. private String ribbonEchoServer;
  5. @Autowired
  6. private RestTemplate restTemplate;
  7. @Autowired
  8. private RestTemplate loadBalancedRestTemplate;
  9. @Autowired
  10. private LoadBalancerClient loadBalancerClient;
  11. @GetMapping("/client")
  12. public String client(String str) {
  13. // 获得服务 `ribbonEchoServer` 的一个实例
  14. ServiceInstance instance = loadBalancerClient.choose(ribbonEchoServer);
  15. if (instance!=null){
  16. // 发起调用
  17. String targetUrl = instance.getUri() + "/echo?s=" + str;
  18. String response = restTemplate.getForObject(targetUrl, String.class);
  19. // 返回结果
  20. return "client:" + response;
  21. }
  22. return "client";
  23. }
  24. @GetMapping("/temp")
  25. public String temp(String str) {
  26. String targetUrl = "http://"+ribbonEchoServer+"/echo?s=" + str;
  27. String response = loadBalancedRestTemplate.getForObject(targetUrl, String.class);
  28. // 返回结果
  29. return "temp:" + response;
  30. }
  31. }

/client 接口,使用 LoadBalancerClient 先选择服务 ribbon-echo-provider 的一个实例,在使用 RestTemplate 调用服务ribbon-echo-provider的 /echo 接口。不过要注意,这里执行会报如下异常:

  1. ava.lang.IllegalStateException: No instances available for 192.168.0.107
  2. at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:119) ~[spring-cloud-netflix-ribbon-2.2.6.RELEASE.jar:2.2.6.RELEASE]
  • 因为我们这里创建的 RestTemplate Bean 是添加了 @LoadBalanced 注解,它会把传入的 “192.168.0.107” 当做一个服务,显然是找不到对应的服务实例,所以会报 IllegalStateException 异常。
  • 解决办法也非常简单,再声明一个未使用 @LoadBalanced 注解的 RestTemplate Bean 即可,并使用它发起请求。

查看nacos服务
image.png

测试
http://localhost:18080/client?str=test
http://localhost:18080/temp?str=test