之前文章我們介紹了如何配置具有Ribbon輪詢機制的負載平衡策略的消費者,這次來具體瞭解一下Ribbon的一些細節,以及如何自訂負載平衡策略等。
說一下Ribbon實現負載平衡的大致思路。它通過用@LoadBalanced修飾RestTemplate,將它交由Ribbon來配置,給RestTemplate定義了一個攔截器,攔截rest請求,交由Ribbon處理後發送出去。Ribbon主要負責選取合適的執行個體,並構造URL。(具體不分析了,有興趣的可以看下LoadBalancerAutoConfiguration,LoadBalancerInterceptor,LoadBalancerClient幾個類)。
我們來看一下,先瞭解以下幾個我們可能用到的重要介面。
ILoadBalancer:Ribbon的負載平衡器介面,定義了增加服務執行個體,選擇服務執行個體,標誌服務執行個體下線,取得當前可用執行個體,取得所有服務執行個體方法。通過方法定義,我們可以看出,這個類是Ribbon的最主要的管理類。它管理所有執行個體,並通過擷取執行個體方法的中的負載平衡策略選擇合適執行個體返回。主要涉及到AbstractLoadBalancer實現介面,並定義了一些基礎方法。
- BaseLoadBalancer:繼承AbstractLoadBalancer,負載平衡器的基礎實作類別,有幾個需要注意的地方:IPing(用於檢測執行個體狀態的方式)對象未實現,為空白,需要在構造時傳入,檢查執行個體狀態的預設策是SerialPingStrategy,該策略會使用傳入規則,輪詢執行個體檢查其狀態,在網路不好或執行個體過多的情況下,會存在效能問題。檢查策略也可以自訂傳入。定義了IRule對象,該對象主要用於定義負載平衡策略,ILoadBalancer會將自己通過建構函式傳入IRule,IRule通過choose函數取得serverList,並返回規則下的某個server。該均衡器預設的IRule為RoundRobinRule,策略為線性輪詢服務執行個體返回。
- NoOpLoadBalancer,這個類繼承AbstractLoadBalancer,從名字可以看出,反正就是什麼也不做。。。
- DynamicServerlistloadBalancer,繼承BaseLoadBalancer,實現了服務資訊清單在運行過程中動態更新的能力,同時具備服務資訊清單過濾的功能。大家可以自己看下,我也沒仔細看>_<。
- ZoneAwareLoadBalancer,繼承DynamicServerlistloadBalancer,功能上是最完善,最強大的,由於DynamicServerlistloadBalancer使用輪詢方式調用執行個體,在地區不同的情況下,可能存在網路延遲等情況影響效能,所以出現了ZoneAwareLoadBalancer,它具有地區親和性,會優先選擇同地區的執行個體。它使用ZoneAvoidanceRule作為負載平衡策略。
IRule:負載平衡策略介面
- AbstractloadBalancerRule,實現了一些基本的方法。定義了ILoadBalancer對象。
- RandomRule:隨機播放策略。
- RoundRobinRule:線性輪詢策略
- RetryRule:內部定義了另一個輪行策略,具備了判斷執行個體選擇檢測執行個體是否存活,未存活時,輪詢選擇其餘執行個體,並判斷執行個體狀態,還設定了逾時功能,在指定時間內,未能選擇出能使用的執行個體,則返回null。
- WeightedResponseTimeRule:對RoundRobinRule的擴充,裡面定義了一個演算法計算執行個體的權重,權重與執行個體回應時間有關,反正最終效果就是回應時間短的執行個體更容易被選擇到。
- ClientConfigEnabledRoundRobinRule:實現和RoundRobinRule一致,用於其他類通過繼承它進行擴充。
- BestAvailableRule繼承於ClientConfigEnabledRoundRobinRule,它通過遍曆所有執行個體,過濾故障執行個體,找出並發請求最少的一個執行個體返回。誰最閑找誰做事。
- PredicateBasedRule:該規則先實現過濾(某種判斷執行個體是否故障,且較閒置演算法),然後遍曆找出一個執行個體。(這個沒怎麼懂)。
- AvailabilityFilteringRule:繼承了PredicateBasedRule,直接遍曆執行個體,根據規則,找到一個合適的執行個體就返回。
- ZoneAvoidanceRule:繼承PredicateBasedRule,具備地區親和性的策略,先通過地區過濾出同地區的執行個體,再選擇一個執行個體。如果沒有同地區的執行個體,則線性遍曆其他執行個體。
IPing:檢測執行個體是否可用的介面
- AbstractLoadBalancerPing:實現IPing,定義了AbstractLoadBalancer。
- NoOpPing:實現IPing,返回true,表示預設所有執行個體可用。
- DummyPing:預設返回true,並構造了一個initWithNiwsConfig空方法,應該是用來提供給開發人員自己繼承實現的類。
- NIWSDiscoveryPing:這個是和Eureka結合使用時,以註冊中心管理的執行個體狀態為準,狀態為UP的執行個體返回為可用。
- PingConstant:實現IPing,可以通過setConstant來設定當前或所有執行個體的狀態。
- PingUrl:實現IPing,通過發送http請求判斷執行個體傳回值的狀態代碼是否為200,判斷執行個體是否存活。預設地址是http或ip:連接埠,可以通過setPingAppendString,往ip後再拼接字元構成地址。
以上三個介面是Ribbon最主要的幾個介面,其餘介面在這裡不做介紹。
下面講一下Ribbon使用的預設介面,注意,與Eureka整合後,介面有一定變化。
- ILoadBalancer,用的ZoneAwareLoadBalancer
- IRule,用的ZoneAvoidanceRule
- IPing,用的NoOpPing,預設都可以
- ServerList<Server>,用的ConfigurationBasedServerList,以配置執行個體列表決定,配置方式為:<servername>.ribbon.listOfServers=localhost:8001,localhost:8002, localhost:8003
- ServerListFilter<Server>,預設使用ZonePreferenceServerListFilter,優先過濾同地區的執行個體。
- IClientConfig,Ribbon的用戶端配置,預設使用DefaultClientConfigimpl
在和Eureka整合後,介面執行個體使用有以下變化:
- ServerList<Server>,由DiscoveryEnabledNIWSServerList替換。該類實現將服務執行個體清單列表的管理交由Eureka的註冊中心維護。表示Ribbon直接從Eureka註冊中心擷取服務列表。
- IPing被.NIWSDiscoveryPing來替換,表示執行個體的狀態由Eureka註冊中心維護,註冊中心列表中執行個體為UP狀態則返回該執行個體可用。
經過上面的介紹之後,我們來看如何自訂這些策略的實作類別。自己如果要實現這些介面也行。
通過查看Ribbon源碼,找到以下這個類,它的建構函式中定義了這些配置的欄位。
public PropertiesFactory() { classToProperty.put(ILoadBalancer.class, "NFLoadBalancerClassName"); classToProperty.put(IPing.class, "NFLoadBalancerPingClassName"); classToProperty.put(IRule.class, "NFLoadBalancerRuleClassName"); classToProperty.put(ServerList.class, "NIWSServerListClassName"); classToProperty.put(ServerListFilter.class, "NIWSServerListFilterClassName"); }
我們可以看到,它支援5個介面的實作類別配置。如:通過<servername>.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule,配置servername的負載平衡策略為隨機播放執行個體。不加服務名的配置則表示全域生效。好叻,寫完了,親測有效哦,大家可以試著定製自己的負載平衡的配置了!