Ribbon :一个基于 HTTP 和 TCP 的客户端的负载均衡工具,它是基于 Netflix Ribbon 实现的
- Ribbon 几乎存在于每个 Spring Cloud 的微服务中,包括 Feign 提供的声明式服务调用也是基于该 Ribbon 实现的
- Ribbon 默认提供很多种负载均衡算法,例如轮询、随机等,或者自定义负载均衡算法
负载均衡的常见方案:
- 集中式负载均衡(服务器负载均衡):即在 consumer 和 provider 之间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至 provider
- 进程内负载均衡(客户端负载均衡):将负载均衡逻辑集成到 consumer,consumer 从服务注册中心获知有哪些地址可用,然后自己再仓这些地址中选择出一个合适的 provider。Ribbon 属于后者,只是一个类库,集成于 consumer 进程,consumer 通过它来获取 provider 的地址
Ribbon 负载均衡策略
- 轮询策略(默认):RoundRobinRule
- 实现原理:每次都顺序取下一个 provider
- 权重轮询策略:WeightedResponseTimeRule
- 根据每个 provider 的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低
- 原理:一开始为轮询策略,并开启一个计时器,每 30 秒收集一个每个 provider 的平均响应时间,当信息足够时,给每个 provider 附上一个权重,并按权重随机选择 provider,越高权重的 provider 会被高概率选中
- 随机策略:RandomRule
- 原理:从 provider 列表中随机选择一个
- 最少并发数策略:BestAvailableRule
- 原理:选择正在请求中的并发数最小的 provider,除非这个 provider 在熔断中
- 重试策略:RetryRule
- 原理:轮询策略的增强版,轮询策略服务不可用时不做处理,重试策略不可用时会重新尝试集群中的其他节点
- 可用性敏感策略:AvailabilityFilteringRule
- 实现原理:过滤掉性能差的 provider
- 第一种:过滤掉在 Eureka 种处于一直连接失败的 provider
- 第二种:过滤掉高并发(繁忙)的 provider
- 实现原理:过滤掉性能差的 provider
- 区域性敏感策略:ZoneAvoidanceRule
- 原理:
- 以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下的区域种选可用的 provider
- 如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选种的权重
- 原理:
Ribbon简单使用
在 Eureka 创建项目的基础上继续新增两个 service-provider:
根据前面一模一样的创建方式,修改端口即可
然后修改 service-consumer ,服务实现使用第二种复载均衡方式,顺便载控制台输出请求地址:
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient; // Ribbon负载均衡
@Override
public Order selectOrderById(Integer id) {
return new Order(id, "order-001", "中国", 123357D,
selectProductListByDiscoveryClient());
}
private List<ProductDto> selectProductListByDiscoveryClient() {
StringBuffer sb = null;
// 根据服务名称获取一个服务
ServiceInstance si = loadBalancerClient.choose("service-provider");
if (null == si) {
return null;
}
// 请求地址
sb = new StringBuffer();
sb.append("http://")
.append(si.getHost())
.append(":")
.append(si.getPort())
.append("/product/list");
// 将请求的地址输出到控制台
System.out.println(sb.toString());
// 封装了返回数据
ResponseEntity<List<ProductDto>> response = restTemplate.exchange(
sb.toString(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<ProductDto>>() {});
return response.getBody();
}
}
多次访问输出,可见默认使用负载策略是轮询:
Ribbon 负载均衡策略设置
1、Ribbon 全局负载均衡设置:在启动类或配置类中注入负载均衡策略对象,所有服务请求均使用该策略
@Bean
public RandomRule randomRule(){
return new RandomRule();
}
2、局部负载均衡设置:
- 修改配置文件指定服务的负载均衡策略
- 格式:服务应用名.ribbon.NFLoadBalancerRuleClassName
# 负载均衡策略
# service-provider 为调用的服务的名称
service-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Ribbon 点对点直连
点对点直连是指绕过注册中心,直接连接服务提供者获取服务,一般测试阶段使用比较多
1、添加依赖:在pom文件中引入Ribbon,需要注意的是如果pom中有Eureka的依赖,则需要去除Eureka的依赖
<!-- netflix ribbon依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、配置文件:配置文件中关闭 Eureka,添加直连的服务地址,如果不设置负载均衡策略默认使用轮询策略
# 负载均衡策略:service-provider为调用的服务的名称
service-provider:
ribbon:
NFLoadBalancerRulerClassName: com.netflix.loadbalancer.RandomRuler
# 服务提供者的地址
listOfServers: http://localhost:7000/product/list,http://localhost:7001/product/list,http://localhost:7002/product/list
# 关闭Eureka,实现Ribbon点对点直连
ribbon:
eureka:
enabled: false #false,关闭;true,开启