• 10.Ribbon 源码分析(springcloud)


    4.1 Ribbon 要做什么事情?
    先通过 "http://" + serviceId + "/info" 我们思考 ribbon 在真正调用之前需要做什么?
    restTemplate.getForObject(“http://provider/info”, String.class);
    想要把上面这个请求执行成功,我们需要以下几步
    1. 拦截该请求;
    2. 获取该请求的 URL 地址 :http://provider/info
    3. 截取 URL 地址中的 provider
    4. 从服务列表中找到 key provider 的服务实例的集合 ( 服务发现 )
    5. 根据 负载均衡算法 选出一个符合的实例
    6. 拿到该实例的 host port ,重构原来 URL 中的 provider
    7. 真正的发送 restTemplate.getForObject(“http://ip:port/info” String.class)
    4.2 Ribbon 负载均衡的测试
    新增 controller

     
    1. package com.it.controller;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.cloud.client.ServiceInstance;
    4. import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. import org.springframework.web.client.RestTemplate;
    8. @RestController
    9. public class ConsumerController {
    10. @Autowired
    11. private RestTemplate restTemplate;
    12. @Autowired
    13. private LoadBalancerClient loadBalancerClient;
    14. @GetMapping("testRibbon")
    15. public String testRibbon(String serviceName){
    16. //正常来讲,需要拿到ip和port 以及路径 才可以用
    17. String url="http://"+serviceName+"/hello";
    18. String forObject = restTemplate.getForObject(url, String.class);
    19. return forObject;
    20. }
    21. /**
    22. * 核心是负载均衡
    23. * @param serviceName
    24. * @return
    25. */
    26. @GetMapping("testRibbonRule")
    27. public String testRibbonRule(String serviceName){
    28. ServiceInstance choose = loadBalancerClient.choose(serviceName);
    29. return choose.toString();
    30. }
    31. }
    访问: http://localhost:8003/testChoose?serviceId=provider
    4.3 choose 方法入手,查看 Ribbon 负载均衡的源码

    走进 getServer()方法

    chooseServer()里面得到 rule 是哪个对象

             

    发现当前的 rule ZoneAvoidanceRule 对象,而他只有一个父类 PredicateBasedRule

    最终进入 PredicateBasedRule 类的 choose()方法

    com.netflix.loadbalancer.AbstractServerPredicate#incrementAndGetModulo

    4.4 负载均衡之前的服务列表是从何而来呢?
    Ribbon 里面有没有服务列表?
    Ribbon 只做负载均衡和远程调用
    服务列表从哪来? 从 eureka
    Ribbon 有一个核心接口 ILoadBalance (承上 (eureka) 启下(Rule ))
    我们发现在负载均衡之前,服务列表已经有数据了

    重点接口 ILoadBalancer

    重点接口 ILoadBalancer

    Ribbon 没有服务发现的功能,但是 eureka 有,所以 ribbon eureka 完美结合

    首先关注这两个集合,就是存放从 eureka 服务端拉取的服务列表然后缓存到本地

    我们去看 DynamicServerListLoadBalancer 类如何获取服务列表,然后放在 ribbon 的缓存里面

     

    ServerList 实现类(DiscoveryEnabledNIWSServerList

    再回到 BaseLoadBalancer 中真正的存放服务列表

    最后我们得知,只有在初始化 DynamicServerListLoadBalancer 类时,去做了服务拉取和缓存
    也就是说并不是服务一启动就拉取了服务列表缓存起来,流程图如下 :
    4.5 Ribbon serverList 缓存起来,脏读怎么处理?
    根据上面缓存服务列表我们得知, ribbon 的每个客户端都会从 eureka-server 中把服务列表缓存起来 , 主要的类是 BaseLoadBalancer ,那么有新的服务上线或者下线,这么保证缓存及时同步呢

    Ribbon 中使用了一个 PING 机制
    eureka 中拿到服务列表,缓存到本地, ribbon 搞了个定时任务,隔一段时间就去循环 ping一下每个服务节点是否存活

    我们查看 IPing 这个接口 

    我们就想看 NIWSDiscoveryPing

    跟着 isAlive 一直往上找,看哪里去修改本地缓存列表

    查看 notifyServerStatusChangeListener 发现只是一个空壳的接口,并没有对缓存的服务节点做出是实际操作,那么到底在哪里修改了缓存列表的值呢? 我们发现在 ribbon 的配置类中 RibbonClientConfiguration 有一个更新服务列表的方法

    定时任务在哪里开始执行的呢?我们查找 doUpdate()方法

    解决脏读机制的总结:
    1. Ping
    2. 更新机制
    都是为了解决脏读的现象而生的
    测试发现:更新机制和 ping 有个重回,而且在 ping 的时候不能运行更新机制,在更新的时 候不能运行 ping 机制,导致我们很难测到 ping 失败的现象!
    Ping 机制做不了事情
    4.6 Ribbon 负载均衡的实现和几种算法【重点】
    ribbon 中有一个核心的负载均衡算法接口 IRule
    1.RoundRobinRule-- 轮询
    请求次数 % 机器数量
    2.RandomRule-- 随机
    3. 权重
    4. iphash
    3.AvailabilityFilteringRule -- 会先过滤掉由于多次访问故障处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对于剩余的服务列表按照轮询的策略进行访问
    4.WeightedResponseTimeRule-- 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越大。刚启动时如果同统计信息不足,则使用轮询的策略,等统计信 息足够会切换到自身规则
    5.RetryRule-- 先按照轮询的策略获取服务,如果获取服务失败则在指定的时间内会进行重试,获取可用的服务
    6.BestAvailableRule -- 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量小的服务
    7.ZoneAvoidanceRule -- 默认规则,复合判断 Server 所在区域的性能和 Server 的可用行选择服务器。
    Ribbon 默认使用哪一个负载均衡算法:ZoneAvoidanceRule :区间内亲和轮询的算法!通过一个 key 来区分
    负载均衡算法:随机 轮训 权重 iphash(响应时间最短算法,区域内亲和(轮训)算法)

  • 相关阅读:
    架构师的 36 项修炼第06讲:架构核心技术之微服务
    C. Element Extermination
    Linux--FTP服务器功能--项目
    开源替代方案的时间(Time Till Open Source Alternative,TTOSA)
    【算法可视化】模拟算法专题
    uni单选radio
    C语言动态内存空间分配
    【安全学习】记一次内网环境渗透
    RSA 简介及 C# 和 js 实现【加密知多少系列】
    Antv/G2 柱状图添加自定义点击事件
  • 原文地址:https://blog.csdn.net/weixin_59334478/article/details/127797100