功能:
将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,从而协同完成工作任务;同时提供客户端负载均衡算法和服务调用
Ribbon作为消费者服务的负载均衡器,有两种使用方式,一种是和RestTemplate相结合,另一种是和OpenFeign相结合,OpenFeign已经默认集成了Ribbon
注意:
- Ribbon使用位置,处于各个服务之间的调用方来配置Ribbon
- 被调用的服务集群,主机名不能带有"_"符号
使用:
pom文件:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
第一种:
使用LoadBalancerClient对象来调用其他服务;LoadBalancerClient对象底层集成了DiscoveryClient对象,底层通过轮询算法来获取对应的连接实例对象
package com.mmy.controller; @RestController public class FindController { //注入LoadBalancerClient,其持有ribbon提供的负载均衡算法 @Autowired private LoadBalancerClient loadBalancerClient; /* 处理/find2的请求并传参serverName -- 值给服务(应用)名称service-a; 然后响应字符串文本给客户端; */ @RequestMapping("/find2") public String find2(String serverName){ //调用ribbon提供的负载均衡算法拿到服务实例 ServiceInstance instance = loadBalancerClient.choose(serverName); //拿到服务实例的IP和端口 String ip = instance.getHost(); int port = instance.getPort(); //拼接出请求url -- service-a服务的/info请求的url String url = "http://"+ip+":"+port+"/info"; //发出请求,并接收service-a服务的/info请求响应的字符串文本 String result = restTemplate.getForObject(url, String.class); //将接收的service-a服务的/info请求响应的字符串文本再响应给客户端 return result; } }
第二种:
借助ribbon来实现调用服务
//第一步:给将RestTemplate注入IOC容器的方法上添加注解@LoadBalanced //配置RestTemplate的bean对象到容器,使用其可以发送请求 @Bean //标注@LoadBalanced注解,表示让ribbon来管理RestTemplate @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); }
//第二步: @RestController public class FindController { //注入RestTemplate,用其发送请求 @Autowired private RestTemplate restTemplate; /* 处理/find3的请求并传参serverName -- 值给服务(应用)名称service-a; 然后响应字符串文本给客户端; */ @RequestMapping("/find3") public String find3(String serverName){ //组装url -- 协议之后不需要ip和端口,直接拼接服务名,ribbon会通过负载均衡算法处理 String url = "http://"+serverName+"/info"; //发出请求,并接收service-a服务的/info请求响应的字符串文本 String result = restTemplate.getForObject(url, String.class); //将接收的service-a服务的/info请求响应的字符串文本再响应给客户端 return result; } }
遇到的bug: java.lang.IllegalStateException: Request URI does not contain a valid hostname 原因:spring.application.name=ribbon_client;被调用方的主机名中不能带有下划线(”_”)负号
实现机制:
1)拦截请求
2)获取请求的url地址:http://服务名/info
3)截取url地址中的服务名
4)从服务列表中找到该名称的服务的实例集合(服务发现)
5)根据负载均衡算法选出一个实例(默认也是轮询算法)
6)拿到该实例的ip和port,替换原来url中的服务名
7)发送真正的请求:restTemplate.getForObject(“url”, String.class)
Ribbon提供的负载均衡算法:
- RoundRobinRule:轮询,请求次数%机器数量。
- RandomRule:随机。
- AvailabilityFilteringRule:会先过滤掉由于多次访问故障处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对于剩余的服务列表按照轮询的策略进行访问。
- WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越大。刚启动时如果同统计信息不足,则使用轮询的策略,等统计信息足够会切换到自身规则。
- RetryRule:先按照轮询的策略获取服务,如果获取服务失败则在指定的时间内会进行重试,获取可用的服务
- BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量小的服务。
- ZoneAvoidanceRule:默认算法,区间内轮询;复合判断服务所在地理区域的性能和服务的可用性来选择服务。
Ribbon负载均衡算法的修改方式:
第一种:修改访问指定服务使用的算法
#service-a被访问的服务名称;值负载均衡算法实现类的完整类路径 服务名.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
第二种:修改访问所有服务使用的算法
//配置IRule接口的具体的实现类的bean对象到容器 @Bean public IRule myRule() { //指定访问所有服务都使用此算法 return new RandomRule(); }
通过将IRule的实现类注入IOC中,覆盖默认的轮询算法,达到更换负载均衡算法的目的