Ribbon, Netflix 公司開源的用於進程通訊場景的通過實戰檢驗的客戶端項目。它提供了遠程調用的負載均衡,網絡狀態檢查和容錯等功能。Ribbon 基於軟件的負載均衡方式與目標集羣中的機器進行通訊。這裏忽略狀態統計部分,健康檢查的邏輯部分,重點分析負載均衡部分。java
須要JAVA Spring Cloud大型企業分佈式微服務雲構建的B2B2C電子商務平臺源碼 一零三八七七四六二六apache
下面是個典型的使用方式開始,先指定一些目標服務器地址,bash
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 處理請求並返回響應。app
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 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;
複製代碼