8.負載均衡器

一、引子

負載均衡策略可以瞭解到ribbon實現的各種負載均衡策略,當然也可以自己實現相應的算法。其中主要的接口IRule中有個定義如下:

public ILoadBalancer getLoadBalancer();

算法使用的server列表以及狀態信息都從它獲取,這裏,就從它開始。

二、接口

ILoadBalancer,從源碼的註釋中很容易看出,它定義負載均衡的操作,並對server進行存儲。接口如下:


public interface ILoadBalancer {
    public void addServers(List<Server> newServers);
    public Server chooseServer(Object key);
    public void markServerDown(Server server);
    public List<Server> getReachableServers();
    public List<Server> getAllServers();
}

那麼ILoadBalancer的實現有哪些,參考下圖:
在這裏插入圖片描述

三、實現

  1. 首先看一下addServer如何實現
    addServers(List newServers)的默認實現爲BaseLoadBalancer,其內部持有兩個list,如下:

    protected volatile List<Server> allServerList;
    protected volatile List<Server> upServerList;
    

    allServerList代表所有的server,
    upServerList代表已經起來的server。
    addServers實現其實也比較簡單,即將server列表付給這兩個成員變量。

  2. 那麼如和區分server是否起來了呢?
    其實實現是比較簡單的,BaseLoadBalancer內部啓動定時任務,每30秒執行一次ping任務,將ping通的server賦給upServerList。
    這裏涉及到的ping就是我們之前說過的ping

  3. 有了上面的實現,那麼剩餘的方法也就很容易了:

     public List<Server> getReachableServers() {
         return Collections.unmodifiableList(upServerList);
     }
     public List<Server> getAllServers() {
         return Collections.unmodifiableList(allServerList);
     }
    

    其實現僅僅是返回相應的成員變量。

  4. 可以看到BaseLoadBalancer有一個子類DynamicServerListLoadBalancer
    從它的名字DynamicServerList可以看出它具有動態更新Server類別的功能,其實這個功能實現比較簡單,就是依賴ServerListUpdater實現的。
    它獲取到server列表後,再委託ServerListFilter進行server過濾,最後設置到BaseLoadBalancer的兩個成員變量中:allServerList,upServerList。
    到這裏,我們來張圖簡單總結一下server列表是如何動態更新的:
    在這裏插入圖片描述

    1. ServerListUpdater通過定時任務發起server列表獲取。
    2. ServerList通過EurekaClient獲取server列表。
    3. EurekaClient發起http請求到EurekaServer,獲取server列表。
    4. ServerListUpdater獲取結果回調ILoadBalancer設置結果。
    5. ILoadBalancer通過ServerListFilter進行過濾。
    6. IPing定時ping,檢測server的活性。
      這裏需要提一點,在狀態統計中LoadBalancerStats持有一個map,對應着zone和server列表,它的更新就來自於上面的流程,即DynamicServerListLoadBalancer最後獲取到server列表後,會對LoadBalancerStats的map進行更新。
  5. ZoneAwareLoadBalancer
    此類繼承自DynamicServerListLoadBalancer,是負載均衡器的最終實現,也是ribbon默認使用的類。它有如下功能:(翻譯自該類的註釋):

    1. 一般來說,當選擇server時能夠避免某個不健康的zone。
    2. 衡量zone健康狀況的關鍵指標是平均活躍請求,即某個zone的平均活躍請求=這個zone中,還未完成的請求/存活的server
      當某個狀況不好的zone慢慢的發生超時的時候(即大量的請求被卡住),這個指標是非常有效的。
    3. 此均衡器將會計算所有的存活的zone的狀況:
      當任何某個zone平均活躍請求達到配置的閾值時,這個zone將會從被從存活列表中移除;
      如果多個zone達到閾值,那麼具有平均server請求量最大的zone將會被移除;
    4. 一旦狀況最壞的zone被移除,那麼將會按照zone具有的實例數量作爲概率來選擇某個zone。
    5. 選擇完zone,將會使用IRule來選擇一個server,默認的實現爲ZoneAvoidanceRule(由於此時只有一個zone,故ZoneAvoidanceRule退化爲AvailabilityFilteringRule)。

    注:ZoneAwareLoadBalancer使用了ZoneAvoidanceRule來實現,對應如下三個方法:

    1. ZoneAvoidanceRule.createSnapshot
    2. ZoneAvoidanceRule.getAvailableZones
    3. ZoneAvoidanceRule.randomChooseZone
    4. 而這三個方法都是靜態方法,ZoneAvoidanceRule也使用了其中的方法來實現zone的排除和篩選,也就是說ZoneAwareLoadBalancer的zone過濾選擇和ZoneAvoidanceRule是一樣的但是ZoneAwareLoadBalancer採用了ZoneAvoidanceRule的靜態方法的方式實現,感覺有些ugly。

    另外,ZoneAwareLoadBalancer持有一個map,爲每個zone都單獨創建了一個BaseLoadBalancer來進行過濾選定一個zone之後的server選擇。

  6. 最後,來看一下核心方法chooseServer是如何實現的,我們已經知道了最終負載均衡的實現是ZoneAwareLoadBalancer,而它也重寫了chooseServer,它的choose過程如下:
    在這裏插入圖片描述
    單個zone的choose過程說明:

    1. 從LoadBalancerStats查詢存活的zone數量。
    2. 發現爲1,調用BaseLoadBalancer的chooseServer
    3. BaseLoadBalancer的實現很簡單,直接委託給具體的Rule來選擇
    4. 最終會使用ZoneAvoidanceRule,而此時zone的數量爲1,ZoneAvoidanceRule的zone過濾選擇功能不起作用,退化爲AvailabilityFilteringRule,即按照server斷路器打開或者併發量過大過濾掉一些server,再輪詢選擇一個。

    多個zone的choose過程說明:

    1. 從LoadBalancerStats查詢存活的zone數量。
    2. 發現>1,則調用ZoneAvoidanceRule進行zone的過濾和挑選。
    3. 挑選好zone之後,跟 單個zone的choose過程一樣了,委託給BaseLoadBalancer來進行具體的server挑選。
發佈了62 篇原創文章 · 獲贊 23 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章