带你了解 Ribbon 负载均衡器的实现

Spring Cloud 中 Ribbon有在 ZuulFeign 中使用,当然也可以通过在RestTemplate的 bean 定义上添加@LoadBalanced注解方式获得一个带有负载均衡更能的RestTemplate

不过实现的方法都大同小异:对HttpClient进行封装,加上实例的”选择“(这个选择的逻辑就是我们所说的负载均衡)。

要学习某个框架的时候,最简单的方案就是:Running+Debugging

跑就是了。

debug 不一定是为了 bug

debug 出真知

Debugging = Learning

选用 Ali Spittel 的一条推文:

screenshot 2020-06-09 at 16.52.36

以 Zuul 路由的线程栈为例

screenshot 2020-06-09 at 15.14.21

调整下顺序:

RetryableRibbonLoadBalancingHttpClient#execute(RibbonApacheHttpRequest, IClientConfig)
RetryableRibbonLoadBalancingHttpClient#executeWithRetry(...)
RetryTemplate#execute(RetryCallback<T, E>, RecoveryCallback<T>)
RetryTemplate#doExecute(RetryCallback<T, E>, RecoveryCallback<T>, RetryState)
RetryTemplate#canRetry(RetryPolicy, RetryContext)
InterceptorRetryPolicy#canRetry(RetryContext)
AbstractLoadBalancingClient#choose(String serviceId)
ZoneAwareLoadBalancer#chooseServer(Object key) //key as serviceId
BaseLoadBalancer#chooseServer(Object key)
PredicateBasedRule#choose(Object key)
AbstractServerPredicate#chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey)
AbstractServerPredicate#apply(Predicate)

分析

Zuul 收到请求经过一系列 Filter 的处理,来到 RibbonRoutingFilter;将请求封装成 RibbonCommandContext,然后使用 context 构建 RibbonCommand。最终调用RibbonCommand#execute()方法,将请求路由到下游。

RibbonCommand持有AbstractLoadBalancerAwareClient的对象,通过该 client 在处理请求和响应。

对于 retryable 的 client(比如此处的RetryableRibbonLoadBalancingHttpClient), 每次处理请求的时候都会创建一个 RetryTemplate对象来处理请求;同时根据RetryPolicy来创建RetryContext对象,用来保存重试的上下文,并 检查实例是否可以进行重试

注意重点就在这里:检查的时候如果重试次数为 0 且要检查的实例为空(说明是第一次请求),这时便会通过负载均衡器客户端(基本都是AbstractLoadBalancingClient的子类)从后端列表择出一个实例,保存在RetryContext中。

负载均衡器客户端使用负载均衡器ILoadBalancer的实现)来选择实例。每个负载均衡器都有自己的规则(IRule的实现类),通过规则来选择实例。

IRule的实现不是很多,

screenshot 2020-06-09 at 16.33.09

其中的ClientConfigEnabledRoundRobinRuleRoundRobinRule的基础上,增加了配置的接口(因为其实现了IClientConfigAware接口)可以对规则进行配置。

某些ClientConfigEnabledRoundRobinRule的子类了,增加了Predicate逻辑:使用PredicateAbstractServerPredicate的子类)的逻辑进行选择;而ClientConfigEnabledRoundRobinRule只是简单的使用RoundRobinRule进行选择。

因此选择的逻辑都是在AbstractServerPredicate子类中,其有个特别的子类CompositePredicate,顾名思义就是将多个逻辑整合在一起(使用Predicate#and()将所有逻辑串联起来,达到&&的效果),所有的逻辑检查都通过(返回true)时,这个实例就会被选中。

screenshot 2020-06-09 at 16.56.42


那么现在要你写个自己负载均衡规则,应该知道从哪里入手了吧?:D


文章同步发送到公众号:云编码 (微信号:sevenfeet)。

qrcode

comments powered by Disqus