Ribbon2核心設計分析
Ribbon 提供基於軟體的負載均衡方式與目標叢集中的機器進行通訊。這裡忽略狀態統計部分,健康檢查的邏輯部分。
下面是個典型的使用方式開始,先指定一些目標伺服器地址,
//sample-client.ribbon.listOfServers=www.taobao.com:80,www.baidu.com:80,www.sina.com:80
然後藉助ribbon 封裝的 httpClient 來傳送請求(訪問站點首頁),迴圈20次是希望列印出負載均衡的效果。
...
RestClient client = (RestClient) ClientFactory.getNamedClient("sample-client");
HttpRequest request = HttpRequest.newBuilder().setUri(new URI("/")).build();
for (int i = 0; i < 20; i++) {
HttpResponse response = client.executeWithLoadBalancer(request);
System.out.println("Status code for " + response.getRequestedURI() + " :" + response.getStatus());
}
下面按 Ribbon 的主要模組進行設計分析,並在最後部分分析上述程式碼的效果。
Ribbon-core 模組
這一模組中,主要定義通用的呼叫抽象。ribbon 的 client 處理請求並返回響應。
public interface IClient<S extends ClientRequest, T extends IResponse> {
public T execute(S request, IClientConfig requestConfig) throws Exception;
}
ClientRequest, 是獨立於所以具體實現的通訊協議的抽象。它主要包括:uri(遠端資源的定位符),loadBalancerKey(Object型別,這是決定請求呼叫到目標伺服器的關鍵資訊),isRetriable; 當然它的具體實現類,可能還有請求headers,body等資訊。
IResponse, 是服務端響應的抽象,主要包括: body(payload),isSuccess(響應狀態的簡化),響應headers,請求url;
VipAddress 術語,是一個地址的邏輯名,該邏輯名代表一系列目標伺服器。比如“apple.bar:80”。
RetryHandler,用來決定哪些異常(比如:ConnectException,SocketTimeoutException)發生時要做重試,哪些異常(SocketException,SocketTimeoutException)發生時表示應該熔斷掉(對應伺服器)的呼叫,預設的是不重試。
Ribbon-loadbalancer 模組
負載均衡,巨集觀上效果是希望將請求的流量均衡(不是簡單意義上的平均)的負載到提供服務的伺服器之上。而對於每次請求而言,是通過計算拿到一個目標伺服器地址的。
- ILoadBalancer
ILoadBalancer, 負載均衡器的介面。它的核心方法是 public Server chooseServer(Object key);
每次請求發生時根據引數傳入的 loadBalancerKey物件,決定出一個目標的伺服器地址。Server 表示一個伺服器(包括:主機地址,埠號以及一些後設資料標識資訊)。 那麼服務均衡器應該需要有一批可供選擇的目標服務集合吧,所以它還有個重要方法 addServers(List<Server> newServers)
,一般在啟動階段就要完成初始化地呼叫。
- BaseLoadBalancer
BaseLoadBalancer(實現 ILoadBalancer),這裡宣告瞭一個基礎lb,應該關聯個 IRule(負載均衡的規則)預設是輪詢規則:RoundRobinRule)。 它還預設支援一個Ping檢查功能(可以幫忙我們定時檢查目標伺服器是否可通訊)的定時任務,開發者可以在構造例項時明確指定 Iping(判斷一個服務是否還是活的),IPingStrateg 預設是序列地檢查策略,但如果目標服務地址過多,或者IPing執行過慢就不太合適。
IRule 路由規則,Rule 和 LoadBalancer 是一對一的相互關聯關係,Rule 是具體的負責均衡策略。常見的規則包括: 輪詢,隨機,基於響應的延遲等; public Server choose(Object key)
核心方法的輸入輸出基本一致,區別是 Rule 拿取目標 server list 是通過藉助對應依賴的 LoadBalancer 拿到的。
- DynamicServerListLoadBalancer
DynamicServerListLoadBalancer(繼承 BaseLoadBalancer),事實上從啟動後一直不變的 ServerList 場景一般不太多,尤其在微服務場景:服務掛了,擴容,縮容等都會需要對服務消費方的客戶端的服務列表做出實時調整(通常藉助服務發現產品:eureka,consul,zk…),DynamicServerListLoadBalancer 顧名思義就是針對該類場景的。要做到執行時實時更新,既要保證更新的實時可見,也要保證更新操作本身的同步。
ServerListUpdater,是動態服務列表的更新器。現實場景中一般有個專門提供釋出和查詢/訂閱服務列表服務的角色,這裡暫時簡稱為”遠端登錄檔服務”。更新 ServerList 常見的有兩種實現模式:push 或者 pull。 push 機制就是客戶端保持對“遠端登錄檔服務”觀察就行,伺服器發生變化時會,客戶端就會及時得到通知。 還有一種 pull 機制,一般是頻繁的發請求進行詢問“遠端登錄檔服務”是否有變化發生。這個一般建議基於常見的服務發現產品進行實現。
ServerListFilter,是DynamicServerListLoadBalancer的可選構造引數之一。作用是在發生 ServerList 更新時篩選過濾出符合條件的一個子集。 因為 ServerList 可能比較大,包含成百上千臺機器地址,如果都嘗試去呼叫,那麼客戶端的連線數就會非常多,這也會造成必要的消耗。
Ribbon-httpclient 模組
ribbon-loadbalancer 模組中有個 ClientFactory 靜態工具類,可以生成和管理多個名字唯一的 IClient 具體例項。ClientFactory.getNamedClient("sample-client");
,這裡因為未特殊配置(指定具體的 IClient 的實現類),所以選擇的是預設的Client實現類 com.netflix.niws.client.http.RestClient。
- RestClient
RestClient,是 ribbon-httpclient 模組中針對 IClient 的具體實現,通過使用 Jesery Client (實際依賴 apacheHttpClient4 傳送 http),同樣 HttpRequest 實現 ClientRequest,而HttpResponse 實現了 ClientResponse。
client.executeWithLoadBalancer(request)
,是client的父類 AbstractLoadBalancerAwareClient 中定義的方法,最終是呼叫 LoadBalancerContext#getServerFromLoadBalancer(URI,loadBalancerKey)
方法,該方法主要LB邏輯如下:
Server svc = lb.chooseServer(loadBalancerKey);
if (svc == null){
throw new ClientException(ClientException.ErrorType.GENERAL,
"Load balancer does not have available server for client: "
+ clientName);
}
//... check host not null
logger.debug("{} using LB returned Server: {} for request {}", new Object[]{clientName, svc, original});
return svc;
相關文章
- 併發程式設計之 SynchronousQueue 核心原始碼分析程式設計原始碼
- CAS原理分析:併發程式設計核心中的核心你瞭解多少?程式設計
- windows核心程式設計--核心物件Windows程式設計物件
- 【乾貨】遊戲介面設計 (一)核心設計遊戲
- windows核心程式設計--程式Windows程式設計
- windows核心程式設計--精華Windows程式設計
- 核心動畫程式設計(一)動畫程式設計
- 核心動畫程式設計(二)動畫程式設計
- Windows核心程式設計_HookWindows程式設計Hook
- python核心程式設計Python程式設計
- C++核心程式設計C++程式設計
- MOBA遊戲分析:LOL和DO他的核心設計邏輯差異遊戲
- windows核心程式設計--纖程Windows程式設計
- windows核心程式設計--DLL基本Windows程式設計
- Windows核心程式設計_磁碟加密Windows程式設計加密
- 讀《Linux核心程式設計》Linux程式設計
- 介面設計分析
- 分析和設計
- python核心程式設計:web伺服器日誌分析簡單指令碼Python程式設計Web伺服器指令碼
- windows核心程式設計--字符集Windows程式設計
- windows核心程式設計--DLL高階Windows程式設計
- linux核心設計與實現Linux
- 《Windows核心程式設計》筆記(一)Windows程式設計筆記
- MR核心程式設計思想總結程式設計
- C++核心程式設計筆記C++程式設計筆記
- 核心程式設計培訓目錄程式設計
- 領域驅動設計核心概念
- 《Linux核心設計與實現》學習【5】—— 核心同步Linux
- 【Linux核心設計與實現】Linux核心簡介Linux
- 產品分析設計
- UI設計案例分析UI
- windows核心程式設計--執行緒池Windows程式設計執行緒
- 軟體測試核心之用例設計
- 《磨難之間》——刻意設計,缺失核心
- Windows核心程式設計(一)-環境搭建Windows程式設計
- 驅動篇——核心程式設計基礎程式設計
- 資料庫:系統設計的核心資料庫
- 程式設計的一些抽象核心程式設計抽象