天天看點

負載均衡算法之輪詢(Round Robin)法和随機(Random)法 Java 代碼實作方法學習

輪詢(Round Robin)法

輪詢排程算法的原理是每一次把來自使用者的請求輪流配置設定給内部中的伺服器,從1開始,直到N(内部伺服器個數),然後重新開始循環。算法的優點是其簡潔性,它無需記錄目前所有連接配接的狀态,是以它是一種無狀态排程。

其代碼實作大緻如下:

import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Set;/**
 * @author [email protected]
 * @date 二月 07, 2017
 */class RoundRobin   {
    private static Integer pos = 0;

    public static String getServer()
    {        // 重建一個Map,避免伺服器的上下線導緻的并發問題
        Map<String, Integer> serverMap =                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);        // 取得Ip位址List
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);        String server = null;
        synchronized (pos)
        {            if (pos > keySet.size())
                pos = 0;
            server = keyList.get(pos);
            pos ++;
        }        return server;
    }
}           

複制

由于serverWeightMap中的位址清單是動态的,随時可能有機器上線、下線或者當機,是以為了避免可能出現的并發問題,方法内部要建立局部變量serverMap,現将serverMap中的内容複制到線程本地,以避免被多個線程修改。這樣可能會引入新的問題,複制以後serverWeightMap的修改無法反映給serverMap,也就是說這一輪選擇伺服器的過程中,新增伺服器或者下線伺服器,負載均衡算法将無法獲知。新增無所謂,如果有伺服器下線或者當機,那麼可能會通路到不存在的位址。是以,服務調用端需要有相應的容錯處理,比如重新發起一次server選擇并調用。

對于目前輪詢的位置變量pos,為了保證伺服器選擇的順序性,需要在操作時對其加鎖,使得同一時刻隻能有一個線程可以修改pos的值,否則當pos變量被并發修改,則無法保證伺服器選擇的順序性,甚至有可能導緻keyList數組越界。

輪詢法的優點在于:試圖做到請求轉移的絕對均衡。

輪詢法的缺點在于:為了做到請求轉移的絕對均衡,必須付出相當大的代價,因為為了保證pos變量修改的互斥性,需要引入重量級的悲觀鎖synchronized,這将會導緻該段輪詢代碼的并發吞吐量發生明顯的下降。

随機(Random)法

通過系統的随機算法,根據後端伺服器的清單大小值來随機選取其中的一台伺服器進行通路。由機率統計理論可以得知,随着用戶端調用服務端的次數增多,

其實際效果越來越接近于平均配置設定調用量到後端的每一台伺服器,也就是輪詢的結果。

随機法的代碼實作大緻如下:

import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Set;/**
 * @author [email protected]
 * @date 二月 07, 2017
 */

 class Random   {
    public static String getServer()
    {        // 重建一個Map,避免伺服器的上下線導緻的并發問題   
        Map<String, Integer> serverMap =                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);        // 取得Ip位址List   
        Set<String> keySet = serverMap.keySet();
        ArrayList<String> keyList = new ArrayList<String>();
        keyList.addAll(keySet);

        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(keyList.size());        return keyList.get(randomPos);
    }
}           

複制

整體代碼思路和輪詢法一緻,先重建serverMap,再擷取到server清單。在選取server的時候,通過Random的nextInt方法取0~keyList.size()區間的一個随機值,進而從伺服器清單中随機擷取到一台伺服器位址進行傳回。基于機率統計的理論,吞吐量越大,随機算法的效果越接近于輪詢算法的效果。