1.概述

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具.
【Ribbon框架自带的负载策略类】

  1. com.netflix.loadbalancer.RoundRobinRule - 轮询
  2. com.netflix.loadbalancer.RandomRule - 随机
  3. com.netflix.loadbalancer.RetryRule - 重试,先按RoundRobinRule进行轮询,如果失败就在指定时间内进行重试
  4. com.netflix.loadbalancer.WeightedResponseTimeRule - 权重,响应速度越快,权重越大,越容易被选中。
  5. com.netflix.loadbalancer.BestAvailableRule - 先过滤掉不可用的处于断路器跳闸转态的服务,然后选择一个并发量最小的服务
  6. com.netflix.loadbalancer.AvailabilityFilteringRule - 先过滤掉故障实例,再选择并发量较小的实例
  7. com.netflix.loadbalancer.ZoneAvoidanceRule - 默认规则,复合判断server所在区域的性能和server的可用性进行服务的选择。

    2.使用案例

    服务端

    服务端无需额外配置,仅仅只要启动服务,将服务注册到nacos注册中心. ```java @RestController @Slf4j @RequestMapping(“/ribbon”) public class RibbonController {
  1. @Value("${server.port}")
  2. private String port;
  3. @GetMapping("/hello")
  4. public String hello(@RequestParam String name) {
  5. return "hello " + name + " come from :" + port;
  6. }

}

  1. <a name="aoAOV"></a>
  2. ## 客户端
  3. <a name="Z8lZh"></a>
  4. ### 初始化RestTemplate
  5. 客户端需要使用**RestTemplate**进行服务的调用.其中 RestTemplate是Spring提供<br />注意:
  6. 1. 使用前需要初始化@Bean交给Spring容器进行管理.
  7. 1. 使用@LoadBalanced 开启客户端负载均衡
  8. ```java
  9. @Configuration
  10. public class RestTemplateConfig {
  11. @LoadBalanced//开启负载均衡
  12. @Bean
  13. RestTemplate getRestTemplate() {
  14. return new RestTemplate();
  15. }
  16. }

注入RestTemplate并调用服务端

  1. @RequestMapping("/ribbon")
  2. @RestController
  3. public class RibbonController {
  4. @Autowired
  5. private RestTemplate restTemplate;
  6. @GetMapping("/hello")
  7. public String hello(@RequestParam String name) {
  8. return restTemplate.getForObject("http://my-product/ribbon/hello?name={name}", String.class, name);
  9. }
  10. }

测试负载均衡

  1. 分别使用端口8003,8009启动2个服务端实例
  2. 启动客户端,并调用 http://localhost:8001/ribbon/hello?name=miaock

注意:使用idea启动多实例,需要开启并行配置
image.png
两次点击显示如下:
image.png

image.png

3.源码解析

源码猜测

  1. 客户端想要进行负载均衡,必须要有服务端的地址列表信息(这里地址列表需要通过心跳定期维护)
  2. 拿到地址列表信息通过负载均衡算法进行选择每次请求要调用的服务地址
  3. 通过http进行请求server端

    源码验证

  4. client客户端对server服务端地址列表如何维护

  5. client客户端对每次server服务端的时候rule的选择
  6. 请求如何通过http进行

验证ribbon负载均衡

通过spring-cloud-starter-alibaba-nacos-discoveryMETA-INF\spring.factories
image.png
image.png
找到 LoadBalancerAutoConfiguration 当前类初始化了RestTemplate
image.png

从代码看出就是针对RestTemplate添加拦截器,拦截后做一些初始化操作
image.png
image.png

  1. 获取负载均衡器
  2. 获取服务端地址
  3. 调用服务端

image.png
通过代码跟进 ILoadBalancer loadBalancer = getLoadBalancer(serviceId);可知ILoadBalancer 是从容器中获取的.那么说明当前ILoadBalancer 肯定是在容器启动的时候进行初始化了.
image.png
通过 org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration 可知.ILoadBalancer默认是ZoneAwareLoadBalancer
image.png
回到刚才位置可知
image.png
image.png
image.png
rule初始化在org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration#ribbonRule
image.png
image.png
通过上面可知,进入到com.netflix.loadbalancer.PredicateBasedRule
image.png
从这里可以知道是通过ILoadBalancer获取所有的server信息,然后通过规则去获取一个返回
lb.getAllServers():从ILoadBalancer获取所有的server的信息.那么server信息哪里得到的?
image.png
image.png
关键点.通过下面可知采用轮询方式进行选则服务
解析:
modulo=1 return 0
modulo=2 return 0 ,1
modulo=3 return 0 ,1 ,2
AtomicInteger类compareAndSet通过原子操作实现了CAS操作,最底层基于汇编语言实现
compareAndSet(expect, update)先进行比较,如果相比较的两个值是相等的,那么就进行更新操作

image.png

验证客户端如何获取server信息

通过上面负载均衡中一段代码,如下
image.png
进去可以看出,列表信息存放在allServerList,现在只需要验证初始化时候获取的信息放在这里一份就ok
image.png
image.png
RibbonClientConfiguration
image.png
image.png
image.png
image.png
最后得到的是所有的服务列表赋值给allServerList.
image.png

验证通过http调用

通过restTemplate.getForObject()进入不难发现接口通过http进行调用
org.springframework.web.client.RestTemplate#getForObject(…)
image.png
image.png

源码流程图

lALPJwY7RlWm_X_NBrLNBpc_1687_1714.png