SpringCloud系列:
- SpringCloud入門必看例子
- 深入了解SpringCloud源碼探究篇 | Eureka服務端源碼分析
- 深入了解SpringCloud源碼探究篇 | Eureka用戶端源碼分析
- 深入了解SpringCloud源碼探究篇 | ribbon源碼分析
- 深入了解SpringCloud源碼探究篇 | Feign源碼分析
下面先利用白話文來描述下ribbon的工作流程
Ribbon:
自動配置類RibbonClientConfiguration和EurekaRibbonClientConfiguration配置類進行各bean轉載包括以下五大元件和ZoneAwareLoadBalancer初始化操作
五大元件:
ServerList:定義擷取伺服器清單 ,預設實作DiscoveryEnabledNIWSServerList
ServerListFilter:對ServerList伺服器清單進行二次過濾 ,預設實作ZonePreferenceServerListFilter
ServerListUpdater: 定義服務更新政策 ,預設實作PollingServerListUpdater
IPing: 檢查服務清單是否存活 預設實作NIWSDiscoveryPing
IRule :根據算法中從服務清單中選取一個要通路的服務 ,預設實作RoundRobinRule
ZoneAwareLoadBalancer: (ILoadBalancer預設的實作),ZoneAwareLoadBalancer是DynamicServerListLoadBalancer的子類,增加zone政策,DynamicServerListLoadBalancer對以上五大元件進行組合使用,調用ServerList接口,DiscoveryEnabledNIWSServerList(預設配置).getInitialListOfServers:從eureka用戶端服務清單緩存中(DiscoveryClient.localRegionApps)擷取服務清單 ;
ServerListUpdater定義服務更新政策 (預設PollingServerListUpdater),這裡DynamicServerListLoadBalancer初始化過程中會傳入自己實作的ServerListUpdater.UpdateAction對象調用ServerListUpdater.start(UpdateAction)啟動一個定時任務,任務中程序調用傳入UpdateAction.doUpdate方法,實際調用的是DynamicServerListLoadBalancer.updateListOfServers方法然後調用ServerList的getUpdatedListOfServers方法進行服務拉取更新,接着updateListOfServers方法裡拿到的服務清單之後會進行調用ServerListFilter的getFilteredListOfServers進行過濾篩選。總而言之就是DynamicServerListLoadBalancer初始化過程中會調用PollingServerListUpdater.start啟動一個定時任務進行實時調用DiscoveryEnabledNIWSServerList.getUpdatedListOfServers去獲DiscoveryClient裡的服務清單緩存(DiscoveryClient.localRegionApps)取最新服務清單接着通過ServerListFilter進行過濾,然後将服務清單setServersList放在自己的緩存allServerList裡(這個是BaseLoadBalancer的allServerList)。接着就是IRule :根據算法中從服務清單中選取一個要通路的服務 ,預設RoundRobinRule輪詢算法。DynamicServerListLoadBalancer實作了ILoadBalancer的chooseServer方法,該實作方法裡調用的就是IRule.choose,自然這裡說的就是RoundRobinRule實作的方法choose,choose調用BaseLoadBalancer擷取到服務緩存清單allServerList,然後進過一系列操作選擇出一個調用的服務進行傳回。
以上提到的五大元件包括ILoadBalancer都是可以通過配置來進行自由選擇實作類:
# 負載均衡類
{服務名}.ribbon.NFLoadBalancerClassName=ZoneAwareLoadBalancer
# 負載均衡規則類
{服務名}.ribbon.NFLoadBalancerRuleClassName=AvailabilityFilteringRule
# 心跳檢測類
{服務名}.ribbon.NFLoadBalancerPingClassName=NIWSDiscoveryPing
# 服務清單類
{服務名}.ribbon.NIWSServerListClassName=DiscoveryEnabledNIWSServerList
# 服務過濾類
{服務名}.ribbon.NIWSServerListFilterClassName=ZonePreferenceServerListFilter
RibbonClientConfiguration配置類
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, name)) {
return this.propertiesFactory.get(IPing.class, config, name);
}
return new DummyPing();
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerList.class, name)) {
return this.propertiesFactory.get(ServerList.class, config, name);
}
ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
return new PollingServerListUpdater(config);
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
return this.propertiesFactory.get(ServerListFilter.class, config, name);
}
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
EurekaRibbonClientConfiguration配置類

這兩個配置類中我們可以發現初始化了ribbon的幾大元件;這裡我們可以看到先是從propertiesFactory配置中擷取對應元件的自定義配置:
以上也證明我們前面提到的可以進行自定義配置個大元件的實作類
ServerList接口
有兩個方法,第一個為初始服務清單擷取,第二個方法為更新緩存服務清單
ServerList定義擷取伺服器清單 ,預設實作DiscoveryEnabledNIWSServerList:
這裡兩個實作方法均是調用obtainServersViaDiscovery方法進行服務清單拉取:
通過調用DiscoveryClient.getInstancesByVipAddress擷取InstanceInfo服務資訊清單:
從上面的調用上可以看到,從 DiscoveryClient的localRegionApps緩存中擷取到服務清單資訊然後進行傳回
ServerListFilter接口
僅提供一個方法
ServerListFilter對ServerList伺服器清單進行二次過濾 ,預設實作ZonePreferenceServerListFilter
ServerListUpdater接口
ServerListUpdater定義服務更新政策,預設實作PollingServerListUpdater:
實作start方法進行開啟一個定時任務,目的就是重新整理ribbon服務清單緩存
實際上調用的是傳入的UpdateAction的doUpdate()方法,該方法在DynamicServerListLoadBalancer被實作重寫,後面再描述
IRule接口
IRule根據算法從服務清單中選取一個要通路的服務 ,預設實作RoundRobinRule輪詢:
以上可以清楚看到從ILoadBalancer的緩存清單allServerList裡擷取出所有的服務,然後進行輪詢選擇一個服務進行傳回
ILoadBalancer
ILoadBalancer是ribbon整個的核心,相當于一個中央控制器,預設實作ZoneAwareLoadBalancer:
ZoneAwareLoadBalancer是DynamicServerListLoadBalancer的子類,增加zone政策,DynamicServerListLoadBalancer對以上五大元件進行組合使用:
我們先來看DynamicServerListLoadBalancer該類被初始化是做了哪些具體操作:
其他的操作均是将五大元件bean指派于DynamicServerListLoadBalancer中,我們重點來看看restOfInit:
該方法調用enableAndInitLearnNewServersFeature以及updateListOfServers,我們先看enableAndInitLearnNewServersFeature:
這裡我們可以清楚看到它調用了ServerListUpdater的start方法,start我們前面已經講到就是啟動了一個定時任務,具體操作線程我們需要看這個傳入的UpdateAction的具體實作,DynamicServerListLoadBalancer實作了ServerListUpdater.UpdateAction:
然後doUpdate實際調用的是自己的updateListOfServers方法:
以上可以清楚看到利用ServerList的實作DiscoveryEnabledNIWSServerList調用getUpdatedListOfServers,該方法前面已經分析過,就是向eureka用戶端的localRegionApps緩存進行服務的拉取操作然後傳回服務清單。
接着調用ServerListFilter的實作進行二次過濾,這裡我就不具體分析這個了。接着就是調用updateAllServerList(servers),然後接着setServersList對服務清單放入進BaseLoadBalancer的allServerList裡
到這裡也就是說DynamicServerListLoadBalancer初始化過程中調用ServerListUpdater.start方法進行啟動一個定時任務來調用updateListOfServers方法,進行服務拉取操作以及過濾。我們回到restOfInit方法啟動任務之後接着下一步還是調用updateListOfServers,其實就是一起動就去拉取服務清單。總而言之就是初始化過程進行服務拉取進自己的allServerList緩存清單中,然後定時進行服務拉取更新操作。
ILoadBalancer的對外提供中比較主要的就是chooseServer方法,用來服務挑選,我們直接看DynamicServerListLoadBalancer的父類BaseLoadBalancer的chooseServer方法:
以上可以看到利用IRule實作的choose進行服務挑選,前面初始化時已經将其實作類RoundRobinRule指派了進來,前面也已經提到過RoundRobinRule的choose方法,這裡不再贅述。
總結
ILoadBalancer被預設初始化ZoneAwareLoadBalancer,然後接着進行向eureka用戶端的localRegionApps緩存中擷取服務清單接着過濾後放入自己的緩存allServerList裡。接着調用ServerListUpdater.start啟動一個定時任務進行服務的拉取更新操作和過濾。在對外提供使用過程中調用chooseServer方法進行調用IRule的choose方法進行服務的挑選和具體服務傳回。