写点什么

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

用户头像
张晓辉
关注
发布于: 2020 年 06 月 09 日
带你了解 Ribbon 负载均衡器的实现

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



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



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



跑就是了。



debug 不一定是为了 bug

debug 出真知

Debugging = Learning

选用 Ali Spittel 的一条推文:





以 Zuul 路由的线程栈为例





调整下顺序:



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的实现不是很多,





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



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



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






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






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





发布于: 2020 年 06 月 09 日阅读数: 52
用户头像

张晓辉

关注

大胆尝试,小心求证 2018.04.09 加入

胡说八道

评论

发布
暂无评论
带你了解 Ribbon 负载均衡器的实现