概述
官方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配置
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<version>2.2.2</version>
</dependency>
Ribbon的常用配置
全局配置
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
指定服务进行配置
与全局配置的区别就是ribbon节点挂在服务名称下面,如下是对ribbon-service调用user-service服务时的单独配置。
user-service:
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
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
在pom.xml 添加相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
application.yaml 配置文件
server:
port: 8201
spring:
application:
name: user-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8001/eureka/
创建
一个服务启动多个实例查看eureka注册中心
调用接口进行测试:http://localhost:8301/user/1
使用nacos
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
没有主动引入 spring-cloud-netflix-ribbon 依赖,因为 spring-cloud-starter-alibaba-nacos-discovery 默认引入了它
application.yaml
server:
port: 18808
spring:
application:
name: ribbon-echo-provider # 应用名
cloud:
nacos:
# Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
创建RibbonEchoController
@RestController
public class RibbonEchoController {
@Value("${server.port}")
private Integer serverPort;
@GetMapping("/echo")
public String echo(String s) throws InterruptedException {
// 模拟执行 100ms 时长。方便后续我们测试请求超时
Thread.sleep(100L);
return serverPort+" [echo]:" + s;
}
}
http://127.0.0.1:18808/echo?s=hello
消费者
@LoadBalanced 注解,声明 RestTemplate Bean 被配置使用 Spring Cloud LoadBalancerClient(负载均衡客户端),实现在请求目标服务时,能够进行负载均衡。
@Configuration
public class RestTemplateConfig {
@Bean(name = "restTemplate")
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean(name = "loadBalancedRestTemplate")
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
return new RestTemplate();
}
}@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
消费端配置信息application.yaml
server:
port: 18080 # 服务器端口。默认为 8080
spring:
application:
name: ribbon-echo-consumer # Spring 应用名
cloud:
nacos:
# Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
service-url:
ribbon-echo-service: ribbon-echo-provider
controller
@RestController
public class EchoLoadBalancerController {
@Value("${service-url.ribbon-echo-service}")
private String ribbonEchoServer;
@Autowired
private RestTemplate restTemplate;
@Autowired
private RestTemplate loadBalancedRestTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/client")
public String client(String str) {
// 获得服务 `ribbonEchoServer` 的一个实例
ServiceInstance instance = loadBalancerClient.choose(ribbonEchoServer);
if (instance!=null){
// 发起调用
String targetUrl = instance.getUri() + "/echo?s=" + str;
String response = restTemplate.getForObject(targetUrl, String.class);
// 返回结果
return "client:" + response;
}
return "client";
}
@GetMapping("/temp")
public String temp(String str) {
String targetUrl = "http://"+ribbonEchoServer+"/echo?s=" + str;
String response = loadBalancedRestTemplate.getForObject(targetUrl, String.class);
// 返回结果
return "temp:" + response;
}
}
/client 接口,使用 LoadBalancerClient 先选择服务 ribbon-echo-provider 的一个实例,在使用 RestTemplate 调用服务ribbon-echo-provider的 /echo 接口。不过要注意,这里执行会报如下异常:
ava.lang.IllegalStateException: No instances available for 192.168.0.107
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服务
测试
http://localhost:18080/client?str=test
http://localhost:18080/temp?str=test