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

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

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

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

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

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

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

  本文講述的是"將外部發(fā)送來(lái)的請(qǐng)求均勻分配到對(duì)稱(chēng)結(jié)構(gòu)中的某一臺(tái)服務(wù)器上"的各種算法,并以Java代碼演示每種算法的具體實(shí)現(xiàn),OK,下面進(jìn)入正題,在進(jìn)入正題前,先寫(xiě)一個(gè)類(lèi)來(lái)模擬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);
    }
}

  輪詢(xún)(Round Robin)法

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

  其代碼實(shí)現(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()
    {
        // 重建一個(gè)Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問(wèn)題
        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中的地址列表是動(dòng)態(tài)的,隨時(shí)可能有機(jī)器上線、下線或者宕機(jī),因此為了避免可能出現(xiàn)的并發(fā)問(wèn)題,方法內(nèi)部要新建局部變量serverMap,現(xiàn)將serverMap中的內(nèi)容復(fù)制到線程本地,以避免被多個(gè)線程修改。這樣可能會(huì)引入新的問(wèn)題,復(fù)制以后serverWeightMap的修改無(wú)法反映給serverMap,也就是說(shuō)這一輪選擇服務(wù)器的過(guò)程中,新增服務(wù)器或者下線服務(wù)器,負(fù)載均衡算法將無(wú)法獲知。新增無(wú)所謂,如果有服務(wù)器下線或者宕機(jī),那么可能會(huì)訪問(wèn)到不存在的地址。因此,服務(wù)調(diào)用端需要有相應(yīng)的容錯(cuò)處理,比如重新發(fā)起一次server選擇并調(diào)用。

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

  輪詢(xún)法的優(yōu)點(diǎn)在于:試圖做到請(qǐng)求轉(zhuǎn)移的絕對(duì)均衡。

  輪詢(xún)法的缺點(diǎn)在于:為了做到請(qǐng)求轉(zhuǎn)移的絕對(duì)均衡,必須付出相當(dāng)大的代價(jià),因?yàn)闉榱吮WCpos變量修改的互斥性,需要引入重量級(jí)的悲觀鎖synchronized,這將會(huì)導(dǎo)致該段輪詢(xún)代碼的并發(fā)吞吐量發(fā)生明顯的下降。

  隨機(jī)(Random)法

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

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

  隨機(jī)法的代碼實(shí)現(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()
    {
        // 重建一個(gè)Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問(wèn)題   
        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);
    }
}

  整體代碼思路和輪詢(xún)法一致,先重建serverMap,再獲取到server列表。在選取server的時(shí)候,通過(guò)Random的nextInt方法取0~keyList.size()區(qū)間的一個(gè)隨機(jī)值,從而從服務(wù)器列表中隨機(jī)獲取到一臺(tái)服務(wù)器地址進(jìn)行返回。基于概率統(tǒng)計(jì)的理論,吞吐量越大,隨機(jī)算法的效果越接近于輪詢(xún)算法的效果。

  源地址哈希(Hash)法

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

  源地址哈希算法的代碼實(shí)現(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()
    {
        // 重建一個(gè)Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問(wèn)題
        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)用中可通過(guò)HttpServlet的getRemoteIp方法獲取
        String remoteIp = "127.0.0.1";
        int hashCode = remoteIp.hashCode();
        int serverListSize = keyList.size();
        int serverPos = hashCode % serverListSize;

        return keyList.get(serverPos);
    }
}

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

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

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

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

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

import java.util.*;

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

    public static String getServer()
    {
        // 重建一個(gè)Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問(wèn)題
        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;
    }
}

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

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

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

import java.util.*;

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

 class WeightRandom   {
    public static String getServer()
    {
        // 重建一個(gè)Map,避免服務(wù)器的上下線導(dǎo)致的并發(fā)問(wèn)題
        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)于是隨機(jī)法和加權(quán)輪詢(xún)法的結(jié)合,比較好理解,就不解釋了。

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

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

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

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

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

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

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

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

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

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

上一篇:iOS開(kāi)發(fā)總結(jié)-Xcode常見(jiàn)錯(cuò)誤

下一篇:編寫(xiě)更好的 Java 單元測(cè)試的 7 個(gè)技巧