Spring-Cloud之Ribbon原理剖析

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

Tags: