前言:
上一篇文章我分析了核心组件的加载过程,这一篇文章主要是分析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里面默认的规则是轮询每个服务实例,然后得到一个服务实例进行远程调用,比较简单,这篇文章就分析到这里,我是程序员老徐,如果喜欢我的文章请点赞关注,下期见。