Ribbon负载均衡
1.为什么需要使用Ribbon
经过学习Consul,我们已经实现了服务的注册和服务发现。当启动某个服务的时候,可以通过HTTP的形式将信息注册到注册中心(Consul),并且可以通过Spring Cloud提供的工具获取注册中心的列表,但是服务之间的调用还存在很多问题:
在微服务不同模块间进行通信时,如何不去硬编码服务提供者的地址?(Consul)
当部署多个相同微服务时,如何实现请求时的负载均衡?(Ribbon)
服务调用者需要针对每个微服务去调用时,需要知道每个微服务的地址和接口,开发难度非常大,怎么解决?
当微服务数量多时,每个又有自己的配置文件,当需要更改配置项时,则每一个都需要更改,怎么去进行配置集中化管理?
在Spring Cloud中,有两种服务调用方式,一种是Ribbon+RestTemplate,另一种是Feign/OpenFeign。
2.在微服务不同模块间希望采用服务名称进行通信
2.1 将访问微服务的路径由ip:port改成服务名称
修改前:static final String PRE_URL=“http://127.0.0.1:8001”;
修改后:static final String PRE_URL=“http://cloud-provider-goods”;
出现问题:通过new RestTemplate()的方式进行远程调用,无法通过服务名进行访问
解决方案:把RestTemplate注册到容器里面
2.2 新建config包,在该包下创建RestConfig类
@Configuration
public class RestConfig {
@Bean
/*
* @LoadBalanced 开启Ribbon客户端负载均衡,以使用LoadBalancerClient来配置它,
* 简而言之,就是RestTemplate发起一个请求,这个请求被LoadBalancerInterceptor给拦截了,
* 拦截后将请求的地址中的服务逻辑名转为具体的服务地址,然后继续执行请求
*/
@LoadBalanced
public RestTemplate getRestTemplate(){
RestTemplate restTemplate=new RestTemplate();
return restTemplate;
}
}
2.3 orderController优化
@RestController
@RequestMapping(“/order”)
public class OrderController {
//根据名称访问微服务
static final String PRE_URL=“http://cloud-provider-goods”;
@Autowired
RestTemplate restTemplate;
@GetMapping("/downOrder/{id}")
public String downOrder(@PathVariable String id){
String result=restTemplate.getForObject(PRE_URL+"/goods/getGoods?id="+id,String.class);
return "下订单成功,购买的书籍信息为:"+result;
}
}
3.负载均衡
负载均衡(Load Balancer,简称LB)是在微服务或分布式集群中常用的一种应用。简单的说就是将用户的请求平摊分配到多个服务器上,从而达到系统的高可用。
通常所说的负载均衡指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。
硬件负载均衡主要通过在服务器节点之间按照专门用于负载均衡的设备,比如F5等;
软件负载均衡则是通过在服务器上安装一些用于负载均衡功能或模块等软件来完成请求分发工作,如Nginx,Lv5等。
4.Ribbon是什么
Ribbon是Netflix发布的一套实现客户端负载均衡的工具。
官网资料: https://github.com/Netflix/ribbon
解释:Ribbon是Netfix发布的开源项目,主要功能是提供客户端的负载均衡算法,将Netfix的中间层服务连接在一起。Ribbon客户端提供一系列完善的配置项,如连接超时,重试等。简单的说就是在配置文件中列出负载均衡(Load Balancer)后面所有机器。Ribbon会自动基于某种规则(如:简单轮询,随机连接等)去连接这些机器,也可以使用Ribbon实现自定义的负载均衡算法。
5.Ribbon架构图
6.Ribbon和Consul整合实现负载均衡操作步骤
6.1 提供3个商品服务提供者
cloud-provider-goods-8001 cloud-provider-goods-8002 cloud-provider-goods-8003
注意:spring.application.name必须相同
参考网址:https://www.pianshen.com/article/90811580638/
6.2 在订单服务消费者cloud-consumer-order-9001中进行Ribbon配置
6.2.1 打开pom.xml中,加入Ribbon启动器依赖(省略该步骤)
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
原因:spring-cloud-starter-consul-discovery
下已经包含spring-cloud-starter-netflix-ribbon,所以无需加入该依赖
6.2.2 在RestConfig类下的getRestTemplate方法上添加
@LoadBalanced,开启Ribbon的负载均衡(前面已经加过,该步骤忽略)
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
RestTemplate restTemplate=new RestTemplate();
return restTemplate;
}
}
6.2.3 测试,查看运行结果
1.启动consul注册中心
2.启动8001 8002 8003 商品微服务提供者
3.启动9001 订单微服务消费者
地址:http://localhost:9001/order/downOrder/1
结论:进行了软负载均衡,且采用的是轮询算法
7 Ribbon核心组件IRule
IRule:根据特定算法中从服务器列表中选取一个要访问的服务,Ribbon默认的算法为轮询算法。
Ribbon中的7种负载均衡算法:
(1)RoundRobinRule:轮询(默认的策略)
(2)RandomRule:随机
(3)AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
(4)WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule
(5)RetryRule:先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
(6)BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
(7)ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器
策略选择:
1.如果微服的每台服务器配置一样,且机器部署在同一个区域,建议考虑轮询策略
2.如果部分机器配置强些,可以考虑修改为WeightedResponseTimeRule
8 如何指定其他的Rule算法(默认轮询)
方式1.在9001消费者的RestConfig类中添加配置
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
RestTemplate restTemplate=new RestTemplate();
return restTemplate;
}
/*指定Rule算法/
@Bean
public IRule myRule(){
return new RandomRule();
}
}
注意:需要重启消费者子模块服务,不然配置不会生效。
方式2.在9001消费者的全局配置文件中进行配置
格式:需要调用的服务名称.ribbon. NFLoadBalancerRuleClassName=负载均载策略的类
cloud-provider-goods:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
9 自定义Ribbon负载均衡算法 参考RandomRule(自学)
网址: https://blog.youkuaiyun.com/weixin_34218890/article/details/86716219
实现案例:依旧轮询策略,但是个服务要求被调用5次后再轮询到下一台服务。
8001 8002 8003
8001 8001 8001 8001 8001 8002…
10 Ribbon 请求重试
大多数情况下,上面的实现没有任何问题,但是总有一些意外发生,比如:有一个实例发生了故障而该情况还没有被服务治理机制及时的发现和摘除,这时候客户端访问该节点的时候自然会失败。所以,为了构建更为健壮的应用系统,我们希望当请求失败的时候能够有一定策略的重试机制,而不是直接返回失败。这个时候就需要实现重试机制
10.1 在9001服务消费者中,打开pom.xml文件,添加重试机制依赖
org.springframework.retry
spring-retry
10.2 修改9001全局配置文件
cloud-provider-goods:
ribbon:
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 250 #请求连接的超时时间
ReadTimeout: 1000 #请求处理的超时时间
OkToRetryOnAllOperations: true #对所有操作请求都进行重试
MaxAutoRetriesNextServer: 1 #切换实例的重试次数
MaxAutoRetries: 1 #对当前实例的重试次数