溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-17 13:58:08 來(lái)源:億速云 閱讀:138 作者:iii 欄目:服務(wù)器

這篇文章主要介紹“服務(wù)器負(fù)載均衡算法怎么實(shí)現(xiàn)”,在日常操作中,相信很多人在服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

負(fù)載平衡(Load balancing)是一種在多個(gè)計(jì)算機(jī)(網(wǎng)絡(luò)、CPU、磁盤(pán))之間均勻分配資源,以提高資源利用的技術(shù)。使用負(fù)載均衡可以最大化服務(wù)吞吐量,可能最小化響應(yīng)時(shí)間,同時(shí)由于使用負(fù)載均衡時(shí),會(huì)使用多個(gè)服務(wù)器節(jié)點(diǎn)代單點(diǎn)服務(wù),也提高了服務(wù)的可用性。

負(fù)載均衡的實(shí)現(xiàn)可以軟件可以硬件,硬件如大名鼎鼎的 F5 負(fù)載均衡設(shè)備,軟件如 NGINX 中的負(fù)載均衡實(shí)現(xiàn),又如 Springcloud Ribbon 組件中的負(fù)載均衡實(shí)現(xiàn)。

如果看到這里你還不知道負(fù)載均衡是干嘛的,那么只能放一張圖了,畢竟沒(méi)圖說(shuō)個(gè)啥。

服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)

負(fù)載均衡要做到在多次請(qǐng)求下,每臺(tái)服務(wù)器被請(qǐng)求的次數(shù)大致相同。但是實(shí)際生產(chǎn)中,可能每臺(tái)機(jī)器的性能不同,我們會(huì)希望性能好的機(jī)器承擔(dān)的請(qǐng)求更多一些,這也是正常需求。

如果這樣說(shuō)下來(lái)你看不懂,那我就再舉個(gè)例子好了,一排可愛(ài)的小熊(服務(wù)器)站好。

服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)

這時(shí)有人(用戶(hù))要過(guò)來(lái)打臉(請(qǐng)求訪(fǎng)問(wèn))。

服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)

那么怎么樣我們才能讓這每一個(gè)可愛(ài)的小熊被打的次數(shù)大致相同呢?

又或者熊 4 比較胖,抗擊打能力是別人的兩倍,我們?cè)趺刺岣咝?4 被打的次數(shù)也是別人的兩倍呢?

又或者每次出手的力度不同,有重有輕,恰巧熊 4 總是承受這種大力度啪啪打臉,熊 4 即將不省熊事,還要繼續(xù)打它嗎?

這些都是值的思考的問(wèn)題。

說(shuō)了那么多,口干舌燥,我雙手已經(jīng)饑渴難耐了,迫不及待的想要擼起代碼了。

1. 隨機(jī)訪(fǎng)問(wèn)

上面說(shuō)了,為了負(fù)載均衡,我們必須保證多次出手后,熊 1 到熊 4 被打次數(shù)均衡。比如使用隨機(jī)訪(fǎng)問(wèn)法,根據(jù)數(shù)學(xué)上的概率論,隨機(jī)出手次數(shù)越多,每只熊被打的次數(shù)就會(huì)越相近。代碼實(shí)現(xiàn)也比較簡(jiǎn)單,使用一個(gè)隨機(jī)數(shù),隨機(jī)訪(fǎng)問(wèn)一個(gè)就可以了。

/** 服務(wù)器列表 */
private static List<String> serverList = new ArrayList<>();
static {
   serverList.add("192.168.1.2");
   serverList.add("192.168.1.3");
   serverList.add("192.168.1.4");
   serverList.add("192.168.1.5");
}

/**
* 隨機(jī)路由算法
*/
public static String random( ) {
   // 復(fù)制遍歷用的集合,防止操作中集合有變更
   List<String> tempList = new ArrayList<>(serverList.size());
   tempList.addAll(serverList);
   // 隨機(jī)數(shù)隨機(jī)訪(fǎng)問(wèn)
   int randomInt = new Random().nextInt(tempList.size());
   return tempList.get(randomInt);
}

因?yàn)槭褂昧朔蔷€(xiàn)程安全的集合,所以在訪(fǎng)問(wèn)操作時(shí)操作的是集合的拷貝,下面幾種輪訓(xùn)方式中也是這種思想。

寫(xiě)一個(gè)模擬請(qǐng)求方法,請(qǐng)求10w次,記錄請(qǐng)求結(jié)果。

public static void main(String[] args) {
   HashMap<String, Integer> serverMap = new HashMap<>();
   for (int i = 0; i < 20000; i++) {
       String server = random();
       Integer count = serverMap.get(server);
       if (count == null) {
           count = 1;
       } else {
           count++;
       }
       // 記錄
       serverMap.put(server, count);
   }
   // 路由總體結(jié)果
   for (Map.Entry<String, Integer> entry : serverMap.entrySet()) {
       System.out.println("IP:" + entry.getKey() + ",次數(shù):" + entry.getValue());
   }
}

運(yùn)行得到請(qǐng)求結(jié)果。

IP:192.168.1.3,次數(shù):24979
IP:192.168.1.2,次數(shù):24896
IP:192.168.1.5,次數(shù):25043
IP:192.168.1.4,次數(shù):25082

每臺(tái)服務(wù)器被訪(fǎng)問(wèn)的次數(shù)都趨近于 2.5w,有點(diǎn)負(fù)載均衡的意思。但是隨機(jī)畢竟是隨機(jī),是不能保證訪(fǎng)問(wèn)次數(shù)絕對(duì)均勻的。

2. 輪訓(xùn)訪(fǎng)問(wèn)

輪訓(xùn)訪(fǎng)問(wèn)就簡(jiǎn)單多了,拿上面的熊1到熊4來(lái)說(shuō),我們一個(gè)接一個(gè)的啪啪 - 打臉,熊1打完打熊2,熊2打完打熊3,熊4打完打熊1,最終也是實(shí)現(xiàn)了被打均衡。但是保證均勻總是要付出代價(jià)的,隨機(jī)訪(fǎng)問(wèn)中需要隨機(jī),輪訓(xùn)訪(fǎng)問(wèn)中需要什么來(lái)保證輪訓(xùn)呢?

/** 服務(wù)器列表 */
private static List<String> serverList = new ArrayList<>();
static {
   serverList.add("192.168.1.2");
   serverList.add("192.168.1.3");
   serverList.add("192.168.1.4");
   serverList.add("192.168.1.5");
}
private static Integer index = 0;

/**
* 隨機(jī)路由算法
*/
public static String randomOneByOne( ) {
   // 復(fù)制遍歷用的集合,防止操作中集合有變更
   List<String> tempList = new ArrayList<>(serverList.size());
   tempList.addAll(serverList);
   String server = "";
   synchronized (index) {
       index++;
       if (index == tempList.size()) {
           index = 0;
       }
       server = tempList.get(index);;
   }
   return server;
}

由代碼里可以看出來(lái),為了保證輪訓(xùn),必須記錄上次訪(fǎng)問(wèn)的位置,為了讓在并發(fā)情況下不出現(xiàn)問(wèn)題,還必須在使用位置記錄時(shí)進(jìn)行加鎖,很明顯這種互斥鎖增加了性能開(kāi)銷(xiāo)。

依舊使用上面的測(cè)試代碼測(cè)試10w次請(qǐng)求負(fù)載情況。

IP:192.168.1.3,次數(shù):25000
IP:192.168.1.2,次數(shù):25000
IP:192.168.1.5,次數(shù):25000
IP:192.168.1.4,次數(shù):25000

3. 輪訓(xùn)加權(quán)

上面演示了輪訓(xùn)方式,還記的一開(kāi)始提出的熊4比較胖抗擊打能力強(qiáng),可以承受別人2倍的挨打次數(shù)嘛?上面兩種方式都沒(méi)有體現(xiàn)出來(lái)熊 4 的這個(gè)特點(diǎn),熊 4 竊喜,不痛不癢。但是熊 1 到 熊 3 已經(jīng)在崩潰的邊緣,不行,我們必須要讓胖著多打,能者多勞,提高整體性能。

/** 服務(wù)器列表 */
private static HashMap<String, Integer> serverMap = new HashMap<>();
static {
   serverMap.put("192.168.1.2", 2);
   serverMap.put("192.168.1.3", 2);
   serverMap.put("192.168.1.4", 2);
   serverMap.put("192.168.1.5", 4);
}
private static Integer index = 0;

/**
* 加權(quán)路由算法
*/
public static String oneByOneWithWeight( ) {
   List<String> tempList = new ArrayList();
   HashMap<String, Integer> tempMap = new HashMap<>();
   tempMap.putAll(serverMap);
   for (String key : serverMap.keySet()) {
       for (int i = 0; i < serverMap.get(key); i++) {
           tempList.add(key);
       }
   }
   synchronized (index) {
       index++;
       if (index == tempList.size()) {
           index = 0;
       }
       return tempList.get(index);
   }
}

這次記錄下了每臺(tái)服務(wù)器的整體性能,給出一個(gè)數(shù)值,數(shù)值越大,性能越好。可以承受的請(qǐng)求也就越多,可以看到服務(wù)器 192.168.1.5 的性能為 4,是其他服務(wù)器的兩倍,依舊 10 w 請(qǐng)求測(cè)試。

IP:192.168.1.3,次數(shù):20000
IP:192.168.1.2,次數(shù):20000
IP:192.168.1.5,次數(shù):40000
IP:192.168.1.4,次數(shù):20000

192.168.1.5 承擔(dān)了 2 倍的請(qǐng)求。

4. 隨機(jī)加權(quán)

隨機(jī)加權(quán)的方式和輪訓(xùn)加權(quán)的方式大致相同,只是把使用互斥鎖輪訓(xùn)的方式換成了隨機(jī)訪(fǎng)問(wèn),按照概率論來(lái)說(shuō),訪(fǎng)問(wèn)量增多時(shí),服務(wù)訪(fǎng)問(wèn)也會(huì)達(dá)到負(fù)載均衡。

/** 服務(wù)器列表 */
private static HashMap<String, Integer> serverMap = new HashMap<>();
static {
   serverMap.put("192.168.1.2", 2);
   serverMap.put("192.168.1.3", 2);
   serverMap.put("192.168.1.4", 2);
   serverMap.put("192.168.1.5", 4);
}
/**
* 加權(quán)路由算法
*/
public static String randomWithWeight( ) {
   List<String> tempList = new ArrayList();
   HashMap<String, Integer> tempMap = new HashMap<>();
   tempMap.putAll(serverMap);
   for (String key : serverMap.keySet()) {
       for (int i = 0; i < serverMap.get(key); i++) {
           tempList.add(key);
       }
   }
   int randomInt = new Random().nextInt(tempList.size());
   return tempList.get(randomInt);
}

依舊 10 w 請(qǐng)求測(cè)試,192.168.1.5 的權(quán)重是其他服務(wù)器的近似兩倍,

IP:192.168.1.3,次數(shù):19934
IP:192.168.1.2,次數(shù):20033
IP:192.168.1.5,次數(shù):39900
IP:192.168.1.4,次數(shù):20133

5. IP-Hash

上面的幾種方式要么使用隨機(jī)數(shù),要么使用輪訓(xùn),最終都達(dá)到了請(qǐng)求的負(fù)載均衡。但是也有一個(gè)很明顯的缺點(diǎn),就是同一個(gè)用戶(hù)的多次請(qǐng)求很有可能不是同一個(gè)服務(wù)進(jìn)行處理的,這時(shí)問(wèn)題來(lái)了,如果你的服務(wù)依賴(lài)于 session ,那么因?yàn)榉?wù)不同, session 也會(huì)丟失,不是我們想要的,所以出現(xiàn)了一種根據(jù)請(qǐng)求端的 ip 進(jìn)行哈希計(jì)算來(lái)決定請(qǐng)求到哪一臺(tái)服務(wù)器的方式。這種方式可以保證同一個(gè)用戶(hù)的請(qǐng)求落在同一個(gè)服務(wù)上。

private static List<String> serverList = 
new ArrayList<>();
static {
   serverList.add("192.168.1.2");
   serverList.add("192.168.1.3");
   serverList.add("192.168.1.4");
   serverList.add("192.168.1.5");
}

/**
* ip hash 路由算法
*/
public static String ipHash(String ip) {
   // 復(fù)制遍歷用的集合,防止操作中集合有變更
   List<String> tempList = new ArrayList<>(serverList.size());
   tempList.addAll(serverList);
   // 哈希計(jì)算請(qǐng)求的服務(wù)器
   int index = ip.hashCode() % serverList.size();
   return tempList.get(Math.abs(index));
}

到此,關(guān)于“服務(wù)器的負(fù)載均衡算法怎么實(shí)現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI