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

 
package com.it.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping("testRibbon")
    public String testRibbon(String serviceName){
        //正常来讲,需要拿到ip和port 以及路径 才可以用
        String url="http://"+serviceName+"/hello";
        String forObject = restTemplate.getForObject(url, String.class);
        return forObject;
    }

    /**
     * 核心是负载均衡
     * @param serviceName
     * @return
     */
    @GetMapping("testRibbonRule")
    public String testRibbonRule(String serviceName){
        ServiceInstance choose = loadBalancerClient.choose(serviceName);
        return choose.toString();
    }


}
访问: 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<T extends Server> 实现类(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(响应时间最短算法,区域内亲和(轮训)算法)

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做一道光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值