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