Spring-Cloud之Ribbon原理剖析

vchar_fred發表於2021-05-13

我們知道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

相關文章