decision插件詳解--核心插件Ribbon負(fù)載均衡器

前言

Ribbon是Netflix發(fā)布的負(fù)載均衡器,在SpringCloud體系中占據(jù)重要的地位,可以單獨(dú)引入使用,也可以配合其他組件使用,比如在Feign中就默認(rèn)集成了Ribbon組件。所以在decision中,對(duì)Ribbon的攔截和增強(qiáng)是其實(shí)現(xiàn)動(dòng)態(tài)路由的核心操作,所以咱們今天從Ribbon的源碼出發(fā),一起來解密decision對(duì)Ribbon做了什么處理,來達(dá)到動(dòng)態(tài)路由的效果。

Ribbon負(fù)載均衡策略

因?yàn)镽ibbon最終是通過RestTemplate對(duì)服務(wù)提供者發(fā)送請(qǐng)求的,所以在使用Ribbon時(shí)需要結(jié)合RestTemplate使用,通常的使用方式如下所示:

@Bean
// Ribbon負(fù)載均衡
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}

在這里大家會(huì)有個(gè)疑問,為啥給RestTemplate添加一個(gè)@LoadBalanced的注解就能夠?qū)崿F(xiàn)負(fù)載均衡呢?接下來我們就來好好分析一下這個(gè)注解背后的操作


通過查看這個(gè)對(duì)這個(gè)注解的描述可以知道,這個(gè)注解是能夠讓一個(gè)RestTemplate對(duì)象被LoadBalancerClient它的實(shí)現(xiàn)類是RibbonLoadBalancerClient)所使用,LoadBalancerClient類是啥呢?這里先放著,按照springboot的套路,我們先分析一下Ribbon的自動(dòng)裝配的過程:

  • 通過spring.factories文件,找到自動(dòng)配置類RibbonAutoConfiguration



    根據(jù)RibbonAutoConfiguration配置類中的裝配順序依次進(jìn)行分析

    • 分析LoadBalancerAutoConfiguration類


      在這里插入圖片描述


      經(jīng)過上述的幾個(gè)步驟,得知添加了注解的RestTemplate對(duì)象會(huì)被添加?個(gè)攔截器
      LoadBalancerInterceptor,所以接下來我們重點(diǎn)分析一下攔截器LoadBalancerInterceptor;

    • 攔截器LoadBalancerInterceptor


      通過分析LoadBalancerInterceptor的intercept方法,得知,最終指向負(fù)載均衡的是LoadBalancerClient對(duì)象的execute方法,而LoadBalancerClient對(duì)象就是上面咱們分析RestTemplate注解里面的注釋中的LoadBalancerClient接口類,其實(shí)現(xiàn)類是RibbonLoadBalancerClient,分析其execute方法:

      最終選擇服務(wù)的方法是getServer(),分析這個(gè)方法,得知最終是調(diào)用ILoadBalancer的chooseServer方法,默認(rèn)實(shí)現(xiàn)類為ZoneAwareLoadBalancer

      ZoneAwareLoadBalancer的chooseServer方法最終調(diào)用的是其父類BaseLoadBalancer的chooseServer

      最終由執(zhí)行IRule的choose方法進(jìn)行選擇,IRule接口的實(shí)現(xiàn)類就是Ribbon對(duì)應(yīng)的幾種負(fù)載均衡方式

      通過分析所有的負(fù)載均衡策略類,最終都會(huì)去調(diào)用ILoadBalancer的getAllservers進(jìn)行過濾,這就是我們的突破口,在這些策略類執(zhí)行之前,我們先把getAllservers的結(jié)果按照header中的參數(shù)進(jìn)行過濾,將過濾后的結(jié)果在交由策略類執(zhí)行,即可達(dá)到我們想要的路由結(jié)果。

    • decison-ribbon-plugin攔截并過濾getAllservers的結(jié)果列表
      由上述可知最終會(huì)調(diào)用ILoadBalancer接口類的getAllServers方法進(jìn)行獲取,ILoadBalancer的實(shí)現(xiàn)類有兩個(gè),其中NoOpLoadBalancer返回是空列表,所以我們關(guān)注另一個(gè)實(shí)現(xiàn)類BaseLoadBalancer,并在decision中對(duì)其進(jìn)行攔截增強(qiáng)


總結(jié)

通過上述分析就完成了decision最核心的動(dòng)態(tài)路由的關(guān)鍵插件,是不是很簡(jiǎn)單呢?但是在這個(gè)看似簡(jiǎn)單的結(jié)果中,我也走了一些彎路,最早時(shí)候,沒有詳細(xì)的去分析Ribbon的源碼,只是一步步的斷點(diǎn)跟蹤調(diào)用棧,最終埋點(diǎn)的位置是在默認(rèn)負(fù)載均衡策略類上,一開始也沒發(fā)現(xiàn)問題,直到有一天,有業(yè)務(wù)組同學(xué)反饋說他的服務(wù)一直沒有按照header的配置進(jìn)行路由選擇,于是我就開始各種排查,最終發(fā)現(xiàn)是它的服務(wù)配置了其他的負(fù)載均衡策略導(dǎo)致的,所以之后我又重新進(jìn)行了一遍源碼閱讀,重新選擇埋點(diǎn)攔截位置,最終解決了該問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容