Ribbon-服务间通信
demo地址
Ribbon负载均衡原理
Ribbon是负载均衡的客户端组件,Ribbon不是HttpClient。Ribbon 还是要配合RestTemplate去用,真正发请求的是RestTemplate
,Ribbon是做负载均衡的。
Ribbon发不了请求,只能做负载均衡
Ribbon 不用主机和端口去调用了,而是以服务名
去调用。
Ribbon组件拿到服务名后会去服务注册中心上找对应的服务id,找到之后Ribbon可以把服务名在注册中心上对应的主机列表拉取到用户服务的本地。
默认负载均衡是轮询的策略。 只有Ribbon组件帮忙确定完一台机器后,RestTemplate才能准确地向这台机器去发对应的请求。
RestTemplate再写机器的主机ip和端口去调用它对应的某个节点,拿到结果之后RestTemplate再返回结果,返回给调用的服务。
Ribbon是客户端的负载均衡,不是服务端的。
因为它不是在注册中心上选择哪台机器,而是把自己的列表拉取到本地之后再去选择某台机器调用。在Ribbon拉取列表到本地的过程中,会把拉取的列表在本地进行缓存,下次不需要在服务注册中心上找了,直接在缓存中找。
如果刚好调用某个服务在注册中心宕了,但是本地缓存中还有,本次调用也是失败的。
缓存也是可以更新的,注册中心会通知缓存列表更新。
基于Ribbon的服务调用
说明
-
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
-
Ribbon springcloud-netflix-ribbon
作用:负载均衡客户端组件 就是用来实现请求调用时负载均衡
注意:ribbon是客户端的负载均衡,它不是在服务注册中心上选择哪台机器,而是把列表拉取到本地之后再去选择某台机器调用
如果ribbon刚从服务注册中心拿完缓存到本地就宕机了,刚好ribbon也轮询到这台宕机的机器了,本次调用就会失败
Ribbon 服务调用
- 项目中引入依赖
如果使用的client中没有ribbon依赖需要显式引入如下依赖
java
<!--引入ribbon依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
- 查看consul client中依赖的ribbon
说明: 如果使用的是eureka client 和 consul client, 无须引入依赖, 因为在eureka, consul中默认集成了ribbon组件
使用 restTemplate + ribbon 进行服务调用
使用Ribbon组件实现负载均衡调用
-
在服务中引用Ribbon依赖 注意:consul client 客户端依赖中已经包含Ribbon
-
直接使用Ribbon组件根据服务id实现请求负载均衡
a. discovery client 服务发现客户端对象 根据服务id去服务注册中心获取对应服务列表到本地中
缺点:没有负载均衡,需要自己实现负载均衡
b. loadBalanceClient 负载均衡客户端对象 根据服务id去服务注册中心获取对应服务列表,根据默认负载均衡策略 选择一台机器进行返回
缺点: 使用时需要先根据服务id获取一个负载均衡机器之后再通过restTemplate调用服务
c. @loadBalanced + RestTemplate 负载均衡客户端注解
修饰范围:用在方法上
作用:让当前方法 当前对象具有Ribbon负载均衡特性
使用discovery Client形式调用
java
//服务注册与发现客户端对象
private DiscoveryClient discoveryClient;
@Autowired
public UserController(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
//获取服务列表
List<ServiceInstance> products = discoveryClient.getInstances("服务ID");
for (ServiceInstance product : products) {
log.info("服务主机:[{}]",product.getHost());
log.info("服务端口:[{}]",product.getPort());
log.info("服务地址:[{}]",product.getUri());
log.info("====================================");
}
使用loadBalance Client形式调用
java
//负载均衡客户端对象
private LoadBalancerClient loadBalancerClient;
@Autowired
public UserLoadBalanceClientController(LoadBalancerClient loadBalancerClient) {
this.loadBalancerClient = loadBalancerClient;
}
//根据负载均衡策略选取某一个服务调用
ServiceInstance product = loadBalancerClient.choose("服务ID");
log.info("服务主机:[{}]",product.getHost());
log.info("服务端口:[{}]",product.getPort());
log.info("服务地址:[{}]",product.getUri());
使用@loadBalanced
java
//1.整合restTemplate + ribbon
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
//2.调用服务位置注入RestTemplate
@Autowired
private RestTemplate restTemplate;
//3.调用
String forObject = restTemplate.getForObject("http://服务ID/hello/hello?name=" + name, String.class);
缺点 (使用RestTemplate+kibbon 这种完成服务间通信)
a. 路径写死在代码中不利于维护
java
restTemplate.getForObject("http://ORDERS/order",String.class);
Ribbon负载均衡策略
java
ribbon负载均衡算法
- RoundRobinRule 轮训策略 按顺序循环选择 Server
- RandomRule 随机策略 随机选择 Server
- AvailabilityFilteringRule 可用过滤策略
`会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
- WeightedResponseTimeRule 响应时间加权策略
`根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高,刚启动时如果统计信息不足,则使用
RoundRobinRule策略,等统计信息足够会切换到
- RetryRule 重试策略
`先按照RoundRobinRule的策略获取服务,如果获取失败则在制定时间内进行重试,获取可用的服务。
- BestAviableRule 最低并发策略
`会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
面试
Ribbon组件实现负载均衡原理 原理:根据调用服务id去服务注册中心获取对应服务id的服务列表,并将服务列表拉取本地进行缓存,然后在本地通过默认的轮询负载均衡策略在现有列表中选择一个可用节点提供服务
注意:Ribbon是客户端负载均衡。Ribbon只是实现负载均衡,真正进行服务间通信的是RestTemplate
Ribbon组件支持哪些负载均衡策略
源码分析:
a. 第一步:查看loadBalanceClient.choose("ORDERS") 源码
b. 第二步: 得知ServiceInstanceChooser是LoadBalanceClient 父接口
c. 第三步: ServiceInstanceChooser的choose方法默认实现RibbonLoadBalancerClient
查看类层级:ctrl + H
d. 第四步: 在RibbonLoadBalancerClient 有一个choose方法带有两个参数 这里面进行负载均衡实现
查看当前类所有的方法 CTRL+F12
e. 查看getServer方法实现
f. 总结通过源码得知IRule是底层负载均衡父接口
java
ribbon负载均衡算法
- RoundRobinRule 轮训策略 按顺序循环选择 Server
- RandomRule 随机策略 随机选择 Server
- AvailabilityFilteringRule 可用过滤策略
`会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
- WeightedResponseTimeRule 响应时间加权策略
`根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高,刚启动时如果统计信息不足,则使用
RoundRobinRule策略,等统计信息足够会切换到
- RetryRule 重试策略
`先按照RoundRobinRule的策略获取服务,如果获取失败则在制定时间内进行重试,获取可用的服务。
- BestAviableRule 最低并发策略
`会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
修改服务的默认负载均衡策略
修改服务默认随机策略
java
# 修改用户服务调用订单服务默认负载均衡策略不在使用轮询 使用随机策略
ORDERS.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
Ribbon组件现在状态
官方停止维护说明
- github.com/Netflix/rib... ribbon-core、ribbon-loadbalance 依然在大规模生产实践中部署,意味着日后如果实现服务间负载均衡依然使用ribbon组件
总结
-
微服务架构第一个组件 服务注册中心: Eureka(NetFlix) Consul(GO) springcloud 可以作为客户端
-
服务间通信手段
a. HTTP 应用层协议 使用 http rest 方式使用json作为数据交换格式进行通信 高度解耦
b. RPC 传输层协议 直接使用对象二进制方式传递数据 效率高耦合度高 java Dubbo
-
springcloud推荐使用 http rest方式进行系统间通信
a. HttpClient对象RestTemplate: 相当java代码中浏览器 HttpClient restTempate.GET POST PUT DELETE PATCH
-
RestTemplate发送请求存在问题
a. 调用地址写死在代码中不利于维护
b. 在调用过程无法实现请求负载均衡
-
微服务架构第个组件: Ribbon组件 NetFlix 作用: 负均衡客户端对象
Ribbon: 仅仅完成是请求的负载均衡节点选择 + RestTemplate
Ribbon原理: 根据请求服务id,先去服务注册中心获取对应服务列表, 然后根据默认轮询策略在选择一台可用节点
Ribbon负裁均衡策略: 通过源码得知Ribbon底层负均衡略父接口IRule父接口,在这个父接口中提供很多负裁均衡策略 轮询 随机 根据响应时间加权 默认是轮询
-
总结
RestTemplate + Ribbon 完成服务间通信 问题: 路径写死不利于不够灵活
-
Ribbon项目状态
Ribbhn-core 、Ribbon-loadBalance 目前还是在大规模生产实践中部署