負載均衡算法

什么是負載均衡

由于微服務架構的廣泛應用,對于負載較高的服務來說,往往對應著多臺服務器組成的集群。請求來臨時,為了將請求均衡的分配到后端服務器,負載均衡程序將從注冊中心查詢可用的服務節點,通過負載均衡算法和規則,選取一臺服務器進行訪問,這個過程稱為服務的負載均衡。

為什么要使用負載均衡

讓所有節點以最小的代價、最好的狀態對外提供服務,快速獲取重要數據,最大化降低了單個節點過載、甚至crash的概率,解決大量并發訪問服務問題;

負載均衡算法

輪詢法

將請求順序輪流分配到節點上;

隨機法

根據節點列表的大小,隨機選擇一臺進行訪問,當請求無限大的時候,效果等同于平均分配;

源地址哈希法

根據客戶端的IP生成一個hash值,與節點列表大小進行取模,當節點列表不發生改變的時候,請求恒打在固定服務器上;

加權輪詢法

不同服務器的配置不同,為其設置權重,使得能者多勞;

加權隨機法

同加權輪詢法

最小連接法

由于后端服務器的配置不同,對于請求響應速度也不同,每次選擇請求積壓條數最少的服務器被選中;

自適應最優選擇方法

這種算法的主要思路是在客戶端本地維護一份同每一個服務節點的性能統計快照,并且每隔一段時間去更新這個快照。在發起請求時,根據“二八原則”,把服務節點分成兩部分,找出 20% 的那部分響應最慢的節點,然后降低權重。這樣的話,客戶端就能夠實時的根據自身訪問每個節點性能的快慢,動態調整訪問最慢的那些節點的權重,來減少訪問量,從而可以優化長尾請求。由此可見,自適應最優選擇算法是對加權輪詢算法的改良,可以看作是一種動態加權輪詢算法。它的實現關鍵之處就在于兩點:第一點是每隔一段時間獲取客戶端同每個服務節點之間調用的平均性能統計;第二點是按照這個性能統計對服務節點進行排序,對排在性能倒數 20% 的那部分節點賦予一個較低的權重,其余的節點賦予正常的權重。

 //負載均衡算法
public class LoadBalancingTest {
    public static final Map<String,Integer> serverWeightMap = new HashMap<>();
    static {
        serverWeightMap.put("127.0.0.1",1);
        serverWeightMap.put("127.0.0.2",1);
        serverWeightMap.put("127.0.0.3",5);
        serverWeightMap.put("127.0.0.4",1);
        serverWeightMap.put("127.0.0.5",1);
        serverWeightMap.put("127.0.0.6",1);
    }
    public static Integer pos = 0;
    public static void main(String[] args) {
        String server = "";
        //輪詢法
        server = polling();
        server = random();
        server = ipHash("127.0.0.1");
        server = weightedPolling();
        server = weightedRandom();
        server = leastConnection();
        System.out.println(server);
    }

    //輪詢法
    private static String polling(){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);
        //獲取IP地址list
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<>();
        keyList.addAll(keySet);

        String server = null;
        synchronized (pos){
            if (pos >= keySet.size()){
                pos = 0;
            }
            server = keyList.get(pos);
            pos++;
        }
        return server;
    }
    //隨機法
    private static String random(){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);
        //獲取IP地址list
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<>();
        keyList.addAll(keySet);

        Random random = new Random();
        int randomPos = random.nextInt(keySet.size());
        String server = keyList.get(randomPos);
        return server;
    }
    //源地址哈希法
    private static String ipHash(String ip){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);
        //獲取IP地址list
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<>();
        keyList.addAll(keySet);

        int hashCode = ip.hashCode();
        int serverPos = hashCode%keySet.size();//keyset 不為null
        String server = keyList.get(serverPos);
        return server;
    }
    //加權輪詢法
    private static String weightedPolling(){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);
        //獲取IP地址list
        Set<String> keySet = serverMap.keySet();
        Iterator<String> it = keySet.iterator();
        ArrayList<String> keyList = new ArrayList<>();
        String server = null;
        while (it.hasNext()){
            server = it.next();
            Integer weight = serverMap.get(server);
            for (int i = 0 ; i < weight ; i++){
                keyList.add(server);
            }
        }
        server = null;
        synchronized (pos){
            if (pos >= keySet.size()){
                pos = 0;
            }
            server = keyList.get(pos);
            pos++;
        }
        return server;
    }
    //加權隨機法
    private static String weightedRandom(){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);
        //獲取IP地址list
        Set<String> keySet = serverMap.keySet();
        Iterator<String> it = keySet.iterator();
        ArrayList<String> keyList = new ArrayList<>();
        String server = null;
        while (it.hasNext()){
            server = it.next();
            Integer weight = serverMap.get(server);
            for (int i = 0 ; i < weight ; i++){
                keyList.add(server);
            }
        }
        Random random = new Random();
        int randomPos = random.nextInt(keyList.size());
        server = keyList.get(randomPos);
        return server;
    }
    //最小連接法,將權重作為連接數在該方法中使用
    private static String leastConnection(){
        //重新創建一個map,避免出現由于服務器上線與下線造成的并發問題
        Map<String,Integer> serverMap = new HashMap<>();
        serverMap.putAll(serverWeightMap);

        String server = null;
        int minConnections = -1;
        for (String key : serverMap.keySet()){
            if (serverMap.get(key)<minConnections){
                minConnections = serverMap.get(key);
                server = key;
            }
        }
        serverMap.put(server,minConnections);
        serverWeightMap.put(server,minConnections);
        return server;
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 記得,我剛工作的時候,同事說了一個故事:在他剛工作的時候,他同事有一天興沖沖的跑到公司說,你們知道嗎,公司請了個大...
    CoderBear閱讀 556評論 0 1
  • 對于要實現高性能集群,選擇好負載均衡器很重要,同時針對不同的業務場景選擇合適的負載均衡算法也是非常重要的。 一、負...
    小manong閱讀 5,181評論 0 2
  • 一、負載均衡算法理論 以下理論知識為互聯網資源的整理,若有侵權,請私信聯系刪除 1. 輪詢算法(Round Rob...
    HRocky閱讀 2,116評論 0 0
  • 概述 比較經典的5種負載均衡算法:隨機法、輪詢法、最少連接數法、最快響應法、Hash化散列法(包括IP-Hash和...
    黃靠譜閱讀 3,010評論 0 33
  • 感覺直接上圖才對得起和我一樣渴望進化的產品Newers。 關于登錄/注冊那件事,用你來總結一下我短暫的PM路不會介...
    用戶運營筆記閱讀 880評論 1 51