幾種負載均衡演算法簡介
首先我們來看一下什麼是負載均衡?
隨著業務的發展,單臺web伺服器已經承載不了系統現在流量的時候,我們就需要部署多臺伺服器,將流量分散在不同的伺服器上,這樣可以提高系統的可用性。
我們可以對web請求進行負載均衡,很大的一部分原因是由於HTTP協議的無狀態性,同樣的請求響應是一樣的,所以哪個伺服器處理都可以(先不考慮session,考慮session的情況,參見我的另一篇部落格)
好了,廢話不多說,我們來看一下有哪些負載均衡演算法:
1.簡單輪詢
顧名思義,這個方法是對後端web伺服器進行簡單的輪詢,將請求按順序發給後端伺服器。
但是我們知道,伺服器的效能可能是不一樣的,每個伺服器此刻處理的請求數量也是不一樣的,這樣簡單地輪詢,可能滿足不了我們系統的要求。因此這個演算法一般作為學習使用。
public class RoundRobin { private static Map<String, Integer> serviceWeightMap = new ConcurrentHashMap<>(); static { serviceWeightMap.put("192.168.1.100", 1); serviceWeightMap.put("192.168.1.101", 1); serviceWeightMap.put("192.168.1.102", 4); serviceWeightMap.put("192.168.1.103", 1); serviceWeightMap.put("192.168.1.104", 1); serviceWeightMap.put("192.168.1.105", 3); serviceWeightMap.put("192.168.1.106", 1); serviceWeightMap.put("192.168.1.107", 2); serviceWeightMap.put("192.168.1.108", 1); serviceWeightMap.put("192.168.1.109", 1); serviceWeightMap.put("192.168.1.110", 1); } private static Integer pos = 0; public static String testRoundRobin() { Set<String> keySet = serviceWeightMap.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; } }
程式碼中為了保證執行緒安全,對伺服器列表做了快照,但是這樣又會引發新的問題,比如我們新增伺服器或者某個伺服器掛掉了,那麼我們的輪詢無法感知。
此外,程式碼中引入了重量級的同步方式synchronized,這樣對與高併發量的業務來說,效能提高不上去。
2.隨機演算法
顧名思義,該演算法就是每來一個請求,從後端伺服器中隨機地選擇一個伺服器處理請求,程式碼如下:
public static String testRandom() { Set<String> keySet = serviceWeightMap.keySet(); ArrayList<String> keyList = new ArrayList<String>(); keyList.addAll(keySet); Random random = new Random(); int randomPos = random.nextInt(keyList.size()); String server = keyList.get(randomPos); return server; }
3.源地址雜湊法
該方法是對客戶端的IP地址做一個Hash,然後對伺服器列表的大小取模,得到處理該請求的伺服器
採用源地址雜湊法進行負載均衡,相同的IP客戶端,如果伺服器列表不變,將對映到同一個後臺伺服器進行訪問
public static String testConsumerHash(String remoteIp) {
Set<String> keySet = serviceWeightMap.keySet();
ArrayList<String> keyList = new ArrayList<String>();
keyList.addAll(keySet);
int hashCode = remoteIp.hashCode();
int pos = hashCode % keyList.size();
return keyList.get(pos);
}
4.加權輪詢法
該方法是在輪詢的基礎上加一個權重,權重高的伺服器處理的請求就多:
public static String testWeightRoundRobin() {
Set<String> keySet = serviceWeightMap.keySet();
Iterator<String> it = keySet.iterator();
List<String> serverList = new ArrayList<String>();
while (it.hasNext()) {
String server = it.next();
Integer weight = serviceWeightMap.get(server);
for (int i=0; i<weight; i++) {
serverList.add(server);
}
Collections.shuffle(serverList);
}
String server = null;
synchronized (pos) {
if (pos > serverList.size()) {
pos = 0;
}
server = serverList.get(pos);
pos++;
}
return server;
}
5.加權隨機法:
該演算法是在隨機演算法的基礎上加一個權重:
public static String testWeightRandom() {
Set<String> keySet = serviceWeightMap.keySet();
List<String> serverList = new ArrayList<String>();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String server = it.next();
Integer weight = serviceWeightMap.get(server);
for (int i=0; i<weight; i++) {
serverList.add(server);
}
}
Random random = new Random();
int randomPos = random.nextInt(serverList.size());
String server = serverList.get(randomPos);
return server;
}
6.最小連線法:
該演算法是檢測那一臺伺服器上的連線數最小,就將請求發給那一臺伺服器:
由於檢測伺服器上連線的程式碼較為複雜,這裡先不列出
思路:先輪詢一遍伺服器列表,得到連線數最小的伺服器,即為處理該請求的伺服器