https://blog.csdn.net/weixin_45481406/article/details/110245642
什么是Ribbon
Ribbon 是一个基于HTTP和TCP的客户端负载均衡工具,它是基于Netflix Ribbon 实现的。它不像Spring Cloud 服务注册中心、配置中心、网关那样独立部署,但是它几乎存在于每个Spring Cloud 微服务中。包括Feign 提供的声明式服务调用也是基于Ribbon实现的。Ribbon默认提供了很多种负载均衡算法,例如:轮询、随机等。甚至可以自定义负载均衡算法。Ribbon提供了一整套微服务的负载均衡解决方案
注意:从Spring Cloud Netflix 3.0 开始,Eureka整合包中已经替换了原来的Ribbon包而是使用的 spring-cloud-starter-loadbalancer,先关的使用也发生了改变
负载均衡方案
目前主流的负载均衡方案可分为两类:
- 集中式负载均衡(服务器负载均衡),即在consumer和provider之间使用独立的负载均衡设施,可以是硬件或软件,由该设施负责把访问请求通过某种策略转发至provider
- 进程内负载均衡(客户端负载均衡),将负载均衡逻辑集成到consumer,consumer从服务注册中心获知哪些地址可用,然后自己再从这些地址中选择合适的provider。Ribbon属于后者,它只是一个类库,集成与consumer中,consumer通过它来获取provider地址
Ribbon 负载均衡策略
1. 轮询策略(默认)
策略对应类名:RoundRobinRule
实现原理:轮询策略表示每次都顺序取下一个provider,例如一共有5个provider,第一次取第一个,第二次取第二个,以此类推。
2. 权重轮询策略
策略对应类名:WeightedResponseTimeRule
实现原理:根据每个provider的响应时间分配一个权重,响应时间越长,权重越低,被选中的可能性越低。权重轮询策略一开始为轮询策略,并开启一个计时器,每30秒收集一次每个provider的平均响应时间,当信息足够时,给每个provider附上一个权重,并按权重随机选择provider,高权重的provider会被高概率选中
3. 随机策略
策略对应类名:****
实现原理:从provider列表中随机选择一个
4. 最少并发数策略
策略对应类名:BestAvailableRule
实现原理:选择正在请求中并发数最少的provider,除非这个provider在熔断中
5. 重试策略
策略对应类名:RetryRule
实现原理:轮询策略的增强版, 轮询策略在服务不可用时是不做处理的,但是重试策略在服务不可用时会重新尝试集群中其他的节点
6. 可用性敏感策略
策略对应类名:AvailabilityFilteringRule
实现原理:过滤性能差的provider,如一直处于连接失败的provider,高并发的provider
7. 区域敏感性策略
策略对应类名:ZoneAvoidanceRule
实现原理:以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选择可用的provider,如果这个IP区域内有一个或多个实例不可达或者响应慢,都会降低该区域内其他IP被选中的权重
注意:从 Spring Cloud Netflix 3.0 以后的版本开始,就已经没有ribbon的依赖,它的负载均衡是依靠的Spring Cloud的负载均衡策略,并且只有两种:轮询策略 和 随机策略,实现的是 ReactorServiceInstanceLoadBalancer 接口,有兴趣的可以去看看源码
Ribbon入门案例
注册中心使用Eureka进行演示,可以参考文章:服务注册与发现-Eureka(三)进行搭建注册中心
本次使用Eureka搭建服务提供者集群,相关代码可在文末的gitee仓库中查看
新版的Eureka默认已经集成了Ribbon因此不用再额外导入jar包
服务消费者测试代码,其他代码可以参考文章:服务注册与发现-Eureka(三)
@Service("consumerDemoService2")
public class ConsumerDemoService2 implements IConsumerDemoService {
// Ribbon负载均衡器
@Autowired
private LoadBalancerClient client;
@Override
public List<DemoEntity> list() {
StringBuffer sb = new StringBuffer();
// 根据服务名称获取服务实例
ServiceInstance instance = client.choose("eureka-provider-demo");
if (ObjectUtils.isEmpty(instance)) return null;
// 根据服务实例信息拼接请求地址
sb.append("http://")
.append(instance.getHost())
.append(":")
.append(instance.getPort())
.append("/list");
// 打印测试
System.out.println(sb.toString());
// 发起http请求
ResponseEntity<List<DemoEntity>> response = new RestTemplate().exchange(sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<DemoEntity>>() {
});
return response.getBody();
}
}
接下来启动测试,给消费者发现请求,从打印的服务提供者地址来看,可以看出默认的是轮询策略
Ribbon 负载均衡策略设置
负载均衡策略默认是 RoundRobinLoadBalancer
public class LoadBalancerConfig {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
}
注意:这个类不能使用 @Configuration 注解,否则负载均衡器会失效并抛出空指针异常