SpringBoot整合Ribbon源码分析之核心组件之间调用流程分析

本文详细分析了Ribbon框架中ZoneAwareLoadBalancer的chooseServer方法,涉及IRule、ZoneAvoidanceRule、轮询算法以及Atomic操作。通过源码展示了默认的轮询策略并讨论了相关数据结构的工作原理。
摘要由CSDN通过智能技术生成

前言:

上一篇文章我分析了核心组件的加载过程,这一篇文章主要是分析Ribbon核心组件的调用过程源码。

还是基于上一篇文章的测试类,略过Feign的源码,直接跳转到Ribbon的源码部分进行分析,直接从ILoadBalancer的实现类ZoneAwareLoadBalancer的chooseServer方法,该方法的截图如下:

我就从这个方法开始进行源码分析。

源码分析:

在chooseServer方法里面调用了IRule对象,这个IRule的默认实现是ZoneAvoidanceRule,在构造函数中创建了一个ZoneAvoidancePredicate对象,把自己当做参数传入到构造函数中,它可以过滤除所有错误的Zone,又创建了一个AvailabilityPredicate对象,把自己当做参数传入到构造函数中,它可以过滤掉所有不可用的服务,又调用createCompositePredicate方法,在该方法中调用CompositePredicate的withPredicates方法把ZoneAvoidancePredicate对象、AvailabilityPredicate对象对象传入,通过建造者模式创建一个
com.netflix.loadbalancer.CompositePredicate.Builder对象,调用build方法得到CompositePredicate对象,ZoneAvoidanceRule构造方法执行完成,调用ZoneAvoidanceRule对象的initWithNiwsConfig对象,配置一些参数。

创建ServerListUpdater对象,默认实现类是PollingServerListUpdater,传入IClientConfig对象,设置refreshIntervalMs为30s,initialDelayMs为1s。

我们看ILoadBalancer的方法发chooseServer的调用过程

判断配置
ZoneAwareNIWSDiscoveryLoadBalancer.enabled是否为true,默认是true的,或者

LoadBalancerStats的可用值小于1会调用父类的chooseServer方法,该方法使得count自增加1,然后调用IRule的choose方法,IRule的实现类是ZoneAvoidanceRule,进入到该类的coose方法,该方法实现如下:

@Override
public Server choose(Object key) {
    ILoadBalancer lb = getLoadBalancer();
    Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
    if (server.isPresent()) {
        return server.get();
    } else {
        return null;
    }       
}

先调用lb.getAllServers()获取所有服务实例列表,然后调用CompositePredicate对象的
chooseRoundRobinAfterFiltering方法,参数是传入服务实例列表,该方法的代码如下:

public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
    List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
    if (eligible.size() == 0) {
        return Optional.absent();
    }
    return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}

该方法内部又调用了getEligibleServers方法,方法的代码如下:

@Override
public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
    List<Server> result = super.getEligibleServers(servers, loadBalancerKey);
    Iterator<AbstractServerPredicate> i = fallbacks.iterator();
    while (!(result.size() >= minimalFilteredServers && result.size() > (int) (servers.size() * minimalFilteredPercentage))
            && i.hasNext()) {
        AbstractServerPredicate predicate = i.next();
        result = predicate.getEligibleServers(servers, loadBalancerKey);
    }
    return result;
}

又调用了父类的AbstractServerPredicate的getEligibleServers方法,返回一个不可修改的服务实例列表,现在假定返回二个服务实例列表方法返回到
chooseRoundRobinAfterFiltering方法调用incrementAndGetModulo方法,该方法的代码如下:

private int incrementAndGetModulo(int modulo) {
    for (;;) {
        int current = nextIndex.get();
        int next = (current + 1) % modulo;
        if (nextIndex.compareAndSet(current, next) && current < modulo)
            return current;
    }
}

其中modulo参数是服务实例数量,这个方法体里面是一个死的for循环,从nextIndex的数据类型AtomicInteger中取出当前值,假如当前nextIndex的值是0,那么current是0,next值是1

比较nextIndex和current值是否相等,如果相等把nextIndex设置为next的值,判断当前的curent值小于modulo,返回当前current的值。

下面做两次请求看看里面的值是怎么变化的。

第一次请求:nextIndex=0, current=0,next=1,比较nextIndex和current值是否相等,很显然这次比较相等把nextIndex设置为1,返回current的值是0。

请二次请求: nextIndex=1, current=1, next=0, 比较nextIndex和current值是否相等,很显然这次比较也相等,又把nextIndex设置为0,返回current的值是0。

由此可以看出这是轮询的算法,每个服务都会被同等的调用到,如果没有自定义IRule的算法,默认是采用轮询算法。

通过这个方法还可以看出一个知识点,就是nextIndex是CAS操作,它是一个原子操作,它是比较内存中的值和当前值是否相等,如果相等把值设置为指定的值,如果不等,会在死循环for中判断直到相等为止才返回。

这样通过一个轮询算法就可以得到一个服务实例对象,然后就可以进行远程调用了。

总结:

本节分析了Ribbon核心组件的调用过程,它是从ILoadBalancer调用开始然后调用到IRule,在IRule里面默认的规则是轮询每个服务实例,然后得到一个服务实例进行远程调用,比较简单,这篇文章就分析到这里,我是程序员老徐,如果喜欢我的文章请点赞关注,下期见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值