我們知道Ribbon主要的工作就是進行負載均衡,幫助我們無需再關注微服務中叢集的地址資訊,因此在原始碼剖析中我們就主要關注這部分的內容。
內建的負載均衡規則
RoundRobinRule
:直接輪詢的方案;即每次從server list中依次選擇。AvailabilityfileringRule
:根據伺服器可用性來決定;比如某個伺服器的併發請求過高,那麼此時ribbon就會繞過不再訪問;同時如果3次連線失敗就會等待30秒後再次訪問;如果不斷失敗,那麼等待時間會不斷變長,如果某個伺服器的併發請求太高了,那麼會繞過去,不再訪問。WeightedResponseTimeRule
:根據權重來分配;每個伺服器都可以有權重,權重高就優先訪問,如果某個伺服器響應時間比較長,那麼權重就會降低,減少訪問。ZoneAvoidanceRule
:根據區域和伺服器來進行負載均衡,也就是根據機房來分配,裡面再使用輪詢的方式。預設的就是這個BestAvailableRule
:忽略連線失敗的伺服器,同時儘量找併發比較低的伺服器來請求。RandomRule
:隨機選擇一個。RetryRule
:在輪詢的方案上增加重試機制;即通過輪詢的方式選擇一個伺服器請求,在失敗的時候會重新再找一個重試。
可以通過ribbon.NFLoadBalancerRuleClassName: top.vchar.MyRule
來切換規則
RestTemplate 加上 @LoadBalanced
當我們在 RestTemplate 上新增 @LoadBalanced 註解後,在寫介面地址的時候可以直接使用服務名代替真實的地址;在執行請求的過程中Ribbon會自動的將其替換為真實的地址。 加上 @LoadBalanced 註解就可以讓 RestTemplate的請求交ribbon的原理如下:
- 在ribbon的整合中有個LoadBalancerAutoConfiguration的配置,它裡面會注入所有帶@LoadBalanced 註解的 RestTemplate的bean;然後會給這些RestTemplate新增上一個LoadBalancerInterceptor的攔截器;
- 在 RestTemplate 執行請求的時候,這個攔截器會攔截請求,將其轉給LoadBalancerClient(實際是RibbonLoadBalancerClient來實現的)來做接下來的全部操作。
- 在RibbonLoadBalancerClient中會根據服務名從登錄檔獲取該服務對應的服務資訊集合,然後根據設定的負載均衡規則選擇一個服務資訊;
- 之後將將請求地址中的服務名稱稱替換為真實的地址,然後發起請求。
IPing機制
Ribbon中IPing機制其實就是定時的去檢查拿到的登錄檔中的服務是否可用,如果不可用將會移除它。預設使用NIWSDiscoveryPing類實現IPing;它就是啟動了一個定時任務,預設每隔30s執行一次,通過檢查服務的狀態是否是UP狀態來判斷該服務是否存活。
public boolean isAlive(Server server) {
boolean isAlive = true;
if (server != null && server instanceof DiscoveryEnabledServer) {
DiscoveryEnabledServer dServer = (DiscoveryEnabledServer)server;
InstanceInfo instanceInfo = dServer.getInstanceInfo();
if (instanceInfo != null) {
InstanceStatus status = instanceInfo.getStatus();
if (status != null) {
isAlive = status.equals(InstanceStatus.UP);
}
}
}
return isAlive;
}
關於Ribbon獲取服務登錄檔
Ribbon並沒有直接使用eureka client的登錄檔資訊,而是拷貝了一份登錄檔資訊重新封裝了一下。 它在初始化的時候會通過PollingServerListUpdater來啟動一個定時任務,預設每隔30s到eureka client的登錄檔中拷貝一次然後重新整理它自己的。這個時間可以通過配置 ribbon.ServerListRefreshInterval 來修改定時任務的執行間隔時間。
那麼如果某臺機器故障當機,ribbon需要多久才能感知到呢?下面我們來分析下:首先eureka server的服務故障感知最壞的情況下是需要180s,同時只讀快取預設30s才會自動更新,eureka client預設30s才會去拉取一次註冊資訊,加上ribbon自己的重新整理時間30s,那麼整個過程需要的時間就是180s+30s+30s+30s=270s,也就是大約要4分鐘半左右。
關於Ribbon的配置
Ribbon配置支援的key在ribbon-core中的CommonClientConfigKey類中,我們可以根據需要到裡面去查閱;配置方式分為全域性和區域性。
- 全部配置直接以ribbon開頭,比如:ribbon.ServerListRefreshInterval:20 修改ribbon重新整理登錄檔的時間
- 區域性配置就是針對某個服務的配置,格式為:
<clientName>.<nameSpace>.<propertyName>=<value>
;示例
# 配置memberServer的服務呼叫失敗的時候重試一次
memberServer.ribbon.MaxAutoRetries=1