中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

多種負載均衡算法及其Java代碼實現(xiàn)

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

  首先給大家介紹下什么是負載均衡(來自百科)

  負載均衡 建立在現(xiàn)有網(wǎng)絡(luò)結(jié)構(gòu)之上,它提供了一種廉價有效透明的方法擴展 網(wǎng)絡(luò)設(shè)備和 服務(wù)器的帶寬、增加 吞吐量、加強網(wǎng)絡(luò)數(shù)據(jù)處理能力、提高網(wǎng)絡(luò)的靈活性和可用性。

  負載均衡,英文名稱為Load Balance,其意思就是分?jǐn)偟蕉鄠操作單元上進行執(zhí)行,例如Web 服務(wù)器、 FTP服務(wù)器、 企業(yè)關(guān)鍵應(yīng)用服務(wù)器和其它關(guān)鍵任務(wù)服務(wù)器等,從而共同完成工作任務(wù)。

  本文講述的是"將外部發(fā)送來的請求均勻分配到對稱結(jié)構(gòu)中的某一臺服務(wù)器上"的各種算法,并以Java代碼演示每種算法的具體實現(xiàn),OK,下面進入正題,在進入正題前,先寫一個類來模擬Ip列表:

import java.util.HashMap;

/**
 * @author [email protected]
 * @date 二月 07, 2017
 */

public class IpMap   {
    // 待路由的Ip列表,Key代表Ip,Value代表該Ip的權(quán)重
    public static HashMap<String, Integer> serverWeightMap =
            new HashMap<String, Integer>();

    static
    {
        serverWeightMap.put("192.168.1.100", 1);
        serverWeightMap.put("192.168.1.101", 1);
        // 權(quán)重為4
        serverWeightMap.put("192.168.1.102", 4);
        serverWeightMap.put("192.168.1.103", 1);
        serverWeightMap.put("192.168.1.104", 1);
        // 權(quán)重為3
        serverWeightMap.put("192.168.1.105", 3);
        serverWeightMap.put("192.168.1.106", 1);
        // 權(quán)重為2
        serverWeightMap.put("192.168.1.107", 2);
        serverWeightMap.put("192.168.1.108", 1);
        serverWeightMap.put("192.168.1.109", 1);
        serverWeightMap.put("192.168.1.110", 1);
    }
}

  輪詢(Round Robin)法

  輪詢調(diào)度算法的原理是每一次把來自用戶的請求輪流分配給內(nèi)部中的服務(wù)器,從1開始,直到N(內(nèi)部服務(wù)器個數(shù)),然后重新開始循環(huán)。算法的優(yōu)點是其簡潔性,它無需記錄當(dāng)前所有連接的狀態(tài),所以它是一種無狀態(tài)調(diào)度。

  其代碼實現(xià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,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問題
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set keySet = serverMap.keySet();
        ArrayList keyList = new ArrayList();
        keyList.addAll(keySet);

        String server = null;
        synchronized (pos)
        {
            if (pos > keySet.size())
                pos = 0;
            server = keyList.get(pos);
            pos ++;
        }

        return server;
    }
}

  由于serverWeightMap中的地址列表是動態(tài)的,隨時可能有機器上線、下線或者宕機,因此為了避免可能出現(xiàn)的并發(fā)問題,方法內(nèi)部要新建局部變量serverMap,現(xiàn)將serverMap中的內(nèi)容復(fù)制到線程本地,以避免被多個線程修改。這樣可能會引入新的問題,復(fù)制以后serverWeightMap的修改無法反映給serverMap,也就是說這一輪選擇服務(wù)器的過程中,新增服務(wù)器或者下線服務(wù)器,負載均衡算法將無法獲知。新增無所謂,如果有服務(wù)器下線或者宕機,那么可能會訪問到不存在的地址。因此,服務(wù)調(diào)用端需要有相應(yīng)的容錯處理,比如重新發(fā)起一次server選擇并調(diào)用。

  對于當(dāng)前輪詢的位置變量pos,為了保證服務(wù)器選擇的順序性,需要在操作時對其加鎖,使得同一時刻只能有一個線程可以修改pos的值,否則當(dāng)pos變量被并發(fā)修改,則無法保證服務(wù)器選擇的順序性,甚至有可能導(dǎo)致keyList數(shù)組越界。

  輪詢法的優(yōu)點在于:試圖做到請求轉(zhuǎn)移的絕對均衡。

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

  隨機(Random)法

  通過系統(tǒng)的隨機算法,根據(jù)后端服務(wù)器的列表大小值來隨機選取其中的一臺服務(wù)器進行訪問。由概率統(tǒng)計理論可以得知,隨著客戶端調(diào)用服務(wù)端的次數(shù)增多,

  其實際效果越來越接近于平均分配調(diào)用量到后端的每一臺服務(wù)器,也就是輪詢的結(jié)果。

  隨機法的代碼實現(xiàn)大致如下:

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,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問題   
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List   
        Set keySet = serverMap.keySet();
        ArrayList keyList = new ArrayList();
        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()區(qū)間的一個隨機值,從而從服務(wù)器列表中隨機獲取到一臺服務(wù)器地址進行返回;诟怕式y(tǒng)計的理論,吞吐量越大,隨機算法的效果越接近于輪詢算法的效果。

  源地址哈希(Hash)法

  源地址哈希的思想是根據(jù)獲取客戶端的IP地址,通過哈希函數(shù)計算得到的一個數(shù)值,用該數(shù)值對服務(wù)器列表的大小進行取模運算,得到的結(jié)果便是客服端要訪問服務(wù)器的序號。采用源地址哈希法進行負載均衡,同一IP地址的客戶端,當(dāng)后端服務(wù)器列表不變時,它每次都會映射到同一臺后端服務(wù)器進行訪問。

  源地址哈希算法的代碼實現(xiàn)大致如下:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author [email protected]
 * @date 二月 07, 2017
 */

 class Hash      {
    public static String getServer()
    {
        // 重建一個Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問題
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set keySet = serverMap.keySet();
        ArrayList keyList = new ArrayList();
        keyList.addAll(keySet);

        // 在Web應(yīng)用中可通過HttpServlet的getRemoteIp方法獲取
        String remoteIp = "127.0.0.1";
        int hashCode = remoteIp.hashCode();
        int serverListSize = keyList.size();
        int serverPos = hashCode % serverListSize;

        return keyList.get(serverPos);
    }
}

  前兩部分和輪詢法、隨機法一樣就不說了,差別在于路由選擇部分。通過客戶端的ip也就是remoteIp,取得它的Hash值,對服務(wù)器列表的大小取模,結(jié)果便是選用的服務(wù)器在服務(wù)器列表中的索引值。

  源地址哈希法的優(yōu)點在于:保證了相同客戶端IP地址將會被哈希到同一臺后端服務(wù)器,直到后端服務(wù)器列表變更。根據(jù)此特性可以在服務(wù)消費者與服務(wù)提供者之間建立有狀態(tài)的session會話。

  源地址哈希算法的缺點在于:除非集群中服務(wù)器的非常穩(wěn)定,基本不會上下線,否則一旦有服務(wù)器上線、下線,那么通過源地址哈希算法路由到的服務(wù)器是服務(wù)器上線、下線前路由到的服務(wù)器的概率非常低,如果是session則取不到session,如果是緩存則可能引發(fā)"雪崩"。如果這么解釋不適合明白,可以看我之前的一篇文章MemCache超詳細解讀,一致性Hash算法部分。

  加權(quán)輪詢(Weight Round Robin)法

  不同的后端服務(wù)器可能機器的配置和當(dāng)前系統(tǒng)的負載并不相同,因此它們的抗壓能力也不相同。給配置高、負載低的機器配置更高的權(quán)重,讓其處理更多的請;而配置低、負載高的機器,給其分配較低的權(quán)重,降低其系統(tǒng)負載,加權(quán)輪詢能很好地處理這一問題,并將請求順序且按照權(quán)重分配到后端。加權(quán)輪詢法的代碼實現(xiàn)大致如下:

import java.util.*;

/**
 * @author [email protected]
 * @date 二月 07, 2017
 */
class WeightRoundRobin   {
    private static Integer pos;

    public static String getServer()
    {
        // 重建一個Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問題
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set keySet = serverMap.keySet();
        Iterator iterator = keySet.iterator();

        List serverList = new ArrayList();
        while (iterator.hasNext())
        {
            String server = iterator.next();
            int weight = serverMap.get(server);
            for (int i = 0; i < weight; i++)
                serverList.add(server);
        }

        String server = null;
        synchronized (pos)
        {
            if (pos > keySet.size())
                pos = 0;
            server = serverList.get(pos);
            pos ++;
        }

        return server;
    }
}

  與輪詢法類似,只是在獲取服務(wù)器地址之前增加了一段權(quán)重計算的代碼,根據(jù)權(quán)重的大小,將地址重復(fù)地增加到服務(wù)器地址列表中,權(quán)重越大,該服務(wù)器每輪所獲得的請求數(shù)量越多。

  加權(quán)隨機(Weight Random)法

  與加權(quán)輪詢法一樣,加權(quán)隨機法也根據(jù)后端機器的配置,系統(tǒng)的負載分配不同的權(quán)重。不同的是,它是按照權(quán)重隨機請求后端服務(wù)器,而非順序。

import java.util.*;

/**
 * @author [email protected]
 * @date 二月 07, 2017
 */

 class WeightRandom   {
    public static String getServer()
    {
        // 重建一個Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問題
        Map<String, Integer> serverMap =
                new HashMap<String, Integer>();
        serverMap.putAll(IpMap.serverWeightMap);

        // 取得Ip地址List
        Set keySet = serverMap.keySet();
        Iterator iterator = keySet.iterator();

        List serverList = new ArrayList();
        while (iterator.hasNext())
        {
            String server = iterator.next();
            int weight = serverMap.get(server);
            for (int i = 0; i < weight; i++)
                serverList.add(server);
        }

        java.util.Random random = new java.util.Random();
        int randomPos = random.nextInt(serverList.size());

        return serverList.get(randomPos);
    }
}

  這段代碼相當(dāng)于是隨機法和加權(quán)輪詢法的結(jié)合,比較好理解,就不解釋了。

  最小連接數(shù)(Least Connections)法

  最小連接數(shù)算法比較靈活和智能,由于后端服務(wù)器的配置不盡相同,對于請求的處理有快有慢,它是根據(jù)后端服務(wù)器當(dāng)前的連接情況,動態(tài)地選取其中當(dāng)前

  積壓連接數(shù)最少的一臺服務(wù)器來處理當(dāng)前的請求,盡可能地提高后端服務(wù)的利用效率,將負責(zé)合理地分流到每一臺服務(wù)器。

  前面幾種方法費盡心思來實現(xiàn)服務(wù)消費者請求次數(shù)分配的均衡,當(dāng)然這么做是沒錯的,可以為后端的多臺服務(wù)器平均分配工作量,最大程度地提高服務(wù)器的利用率,但是實際情況是否真的如此?實際情況中,請求次數(shù)的均衡真的能代表負載的均衡嗎?這是一個值得思考的問題。

  上面的問題,再換一個角度來說就是:以后端服務(wù)器的視角來觀察系統(tǒng)的負載,而非請求發(fā)起方來觀察。最小連接數(shù)法便屬于此類。

  最小連接數(shù)算法比較靈活和智能,由于后端服務(wù)器的配置不盡相同,對于請求的處理有快有慢,它正是根據(jù)后端服務(wù)器當(dāng)前的連接情況,動態(tài)地選取其中當(dāng)前積壓連接數(shù)最少的一臺服務(wù)器來處理當(dāng)前請求,盡可能地提高后端服務(wù)器的利用效率,將負載合理地分流到每一臺機器。由于最小連接數(shù)設(shè)計服務(wù)器連接數(shù)的匯總和感知,設(shè)計與實現(xiàn)較為繁瑣,此處就不說它的實現(xiàn)了。

  附了一個說明“NGINX的實現(xiàn)原因,大家可以看看":

  http://blog.csdn.net/zhangskd/article/details/50242241

標(biāo)簽: ftp服務(wù)器 代碼 訪問服務(wù)器 服務(wù)器 服務(wù)器地址 服務(wù)器選擇 網(wǎng)絡(luò) 應(yīng)用服務(wù)器

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:iOS開發(fā)總結(jié)-Xcode常見錯誤

下一篇:編寫更好的 Java 單元測試的 7 個技巧