更新時間:2020年11月19日17時51分 來源:傳智播客 瀏覽次數(shù):
前面我們使用Ribbon實(shí)現(xiàn)負(fù)載均衡時,基本用法是注入一個RestTemplate,并使用@LoadBalanced注解標(biāo)注RestTemplate,從而使RestTemplate具備負(fù)載均衡的能力。
當(dāng)Spring容器啟動時,使用@LoadBalanced注解修飾的RestTemplate會被添加攔截器,攔截器中使用了LoadBalancerClient處理請求,從而達(dá)到負(fù)載均衡的目的。那么LoadBalancerClient內(nèi)部是如何做到的呢?下面我們通過源碼分析的方式來剖析Ribbon負(fù)載均衡的工作原理。
LoadBalancerClient是Spring Cloud提供的一個非常重要的接口,它繼承自ServiceInstanceChooser接口,該接口的實(shí)現(xiàn)類是RibbonLoadBalanceClient,它們之間的關(guān)系如下圖所示。
LoadBalancerClient的父接口和實(shí)現(xiàn)類
為了大家更好地理解圖3-8所示接口及其實(shí)現(xiàn)類的實(shí)現(xiàn)細(xì)節(jié),我們先查看LoadBalancerClient的部分源碼,具體如下:
public interface LoadBalancerClient extends ServiceInstanceChooser { <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException; URI reconstructURI(ServiceInstance instance, URI original); }
上述源碼中,LoadBalancerClient提供的兩個execute()方法用于執(zhí)行請求, reconstructURI()方法用于重構(gòu)URL。
繼續(xù)查看LoadBalancerClient繼承的ServiceInstanceChooser接口源碼,具體如下:
public interface ServiceInstanceChooser { ServiceInstance choose(String serviceId); }
上述源碼中,ServiceInstanceChooser接口定義一個choose()方法,該方法用于根據(jù)serviceId選擇一個服務(wù)實(shí)例,即通過服務(wù)名選擇服務(wù)實(shí)例。
RibbonLoadBalanceClient是LoadBalancerClient的實(shí)現(xiàn)類,它用來執(zhí)行最終的負(fù)載均衡請求。其中,RibbonLoadBalanceClient的一個choose()方法用于選擇具體的服務(wù)實(shí)例,其內(nèi)部是通過getServer()方法交給ILoadBalancer完成的。
ILoadBalancer是一個接口,該接口定義了一系列實(shí)現(xiàn)負(fù)載均衡的方法。ILoadBalancer接口的實(shí)現(xiàn)類結(jié)果如下圖所示。
ILoadBalancer接口實(shí)現(xiàn)類結(jié)構(gòu)
查看BaseLoadBalancer和DynamicServerListLoadBalancer源碼,默認(rèn)情況下實(shí)現(xiàn)了以下配置:
(1)IClientConfig clientConfig:用于配置負(fù)載均衡客戶端,默認(rèn)實(shí)現(xiàn)類是DefaultClientConfigImpl。
(2)IRule rule:用于配置負(fù)載均衡的策略,默認(rèn)使用的是RoundRobinRule策略,也就是輪詢策略。
(3)IPing ping:用于檢查當(dāng)前服務(wù)是否有響應(yīng),從而判斷當(dāng)前服務(wù)是否可用,默認(rèn)實(shí)現(xiàn)類是DummyPing,該實(shí)現(xiàn)類的isAlive()方法返回值是true,默認(rèn)所有服務(wù)實(shí)例都是可用的。
(4)ServerList serverList: 用于獲取所有Server注冊列表信息。通過跟蹤源碼會發(fā)現(xiàn),ServerList的實(shí)現(xiàn)類是DiscoveryEnabledNIWSServerList,該類定義的obtainServersViaDiscovery()方法是根據(jù)eurekaClientProvider.get()方法獲取EurekaClient,再根據(jù)EurekaClient獲取服務(wù)注冊列表信息。EurekaClient的實(shí)現(xiàn)類是DiscoveryClient,DiscoveryClient具有服務(wù)注冊、獲取服務(wù)注冊列表等功能。
(5)ServerListFilter filter:定義了根據(jù)配置過濾或者動態(tài)獲取符合條件的服務(wù)列表,默認(rèn)實(shí)現(xiàn)類是ZonePreferenceServerListFilter,該策略能夠優(yōu)先過濾出與請求調(diào)用方處于同區(qū)域的服務(wù)實(shí)例。
綜上所述,使用RibbonLoadBalanceClient實(shí)現(xiàn)負(fù)載均衡時,會從EurekaClient獲取服務(wù)列表信息,然后根據(jù)IPing判斷服務(wù)是否可用。如果服務(wù)可用,則會根據(jù)IRule選擇負(fù)載均衡策略,否則會重新獲取服務(wù)清單。
了解了LoadBalancerClient負(fù)載均衡功能后,那么RestTemplate添加@LoadBalanced注解后,為什么會被攔截呢?這是因?yàn)長oadBalancerAutoConfiguration類維護(hù)了一個被@LoadBalanced修飾的RestTemplate列表,在初始化過程中,通過調(diào)用customizer.customize(restTemplate)方法為RestTemplate添加了LoadBalancerInterceptor攔截器,該攔截器中的方法將遠(yuǎn)程服務(wù)調(diào)用的方法交給了LoadBalancerClient去處理,從而達(dá)到了負(fù)載均衡的目的。
猜你喜歡
北京校區(qū)