聊聊六種負載均衡算法
負載均衡(Load Balancing)是一種計算機網絡和服務器管理技術,旨在分配網絡流量、請求或工作負載到多個服務器或資源,以確保這些服務器能夠高效、均勻地處理負載,并且能夠提供更高的性能、可用性和可擴展性。
這篇文章,我們聊聊六種通用的負載均衡算法。

1 輪詢 (Round Robin)
輪詢是指將請求按順序輪流地分配到后端服務器上,它均衡地對待后端的每一臺服務器,而不關心服務器實際的連接數和當前的系統負載。

示例代碼:
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class RoundRobin {
private final List<String> servers;
private final AtomicInteger index = new AtomicInteger(0);
public RoundRobin(List<String> servers) {
this.servers = servers;
}
public String getServer() {
int currentIndex = index.getAndIncrement() % servers.size();
return servers.get(currentIndex);
}
}
2 粘性輪詢 (Sticky Round-Robin)
粘性輪詢是標準輪詢算法的一個變種,它通過記住客戶端與服務實例的映射關系,確保來自同一客戶端的連續請求會被路由到同一個服務實例上。
它的特點是:
- 會話保持:一旦客戶端首次請求被分配到某個服務實例,后續請求會"粘"在這個實例上
- 客戶端識別:通常基于客戶端IP、會話ID或特定HTTP頭來識別客戶端
- 故障轉移:當目標服務實例不可用時,系統會重新分配客戶端到其他可用實例

示例代碼:
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class StickyRoundRobin {
private final List<String> servers;
private final AtomicInteger index = new AtomicInteger(0);
private final Map<String, String> clientToServer = new ConcurrentHashMap<>();
public StickyRoundRobin(List<String> servers) {
this.servers = servers;
}
public String getServer(String clientId) {
return clientToServer.computeIfAbsent(clientId,
k -> servers.get(index.getAndIncrement() % servers.size()));
}
}
3 加權輪詢 (Weighted Round-Robin)
加權輪詢是標準輪詢算法的增強版本,它允許管理員為每個服務實例分配不同的權重值。權重越高的實例處理越多的請求,從而實現更精細的負載分配。

它的特點是:
- 權重分配:每個服務實例都有對應的權重值
- 比例分配:請求按權重比例分配到不同實例
- 動態調整:權重可以動態修改以適應不同場景
示例代碼:
private static Map<String, Integer> serverMap = new ConcurrentHashMap<>();
//記錄服務器權重總和
private static int totalWeight = 0;
public static String weightRandom() {
//獲取服務器數量
int serverCount = serverMap.size();
//如果沒有可用的服務器返回null
if (serverCount == 0) {
return null;
}
//在此處為避免多線程并發操作造成錯誤,在方法內部進行鎖操作
synchronized (serverMap) {
//計算服務器權重總和
for (Map.Entry<String, Integer> entry : serverMap.entrySet()) {
totalWeight += entry.getValue();
}
//生成一個隨機數
int randomWeight = new Random().nextInt(totalWeight);
//遍歷服務器列表,根據服務器權重值選擇對應地址
for (Map.Entry<String, Integer> entry : serverMap.entrySet()) {
String serverAddress = entry.getKey();
Integer weight = entry.getValue();
randomWeight -= weight;
if (randomWeight < 0) {
return serverAddress;
}
}
}
//默認返回null
return null;
}
public class WeightRandomLoadBalancer implements LoadBalancer {
private List<String> servers = new ArrayList<>();
private Map<String, Integer> weightMap = new HashMap<>();
public WeightRandomLoadBalancer(Map<String, Integer> servers) {
this.servers.addAll(servers.keySet());
for (String server : servers.keySet()) {
int weight = servers.get(server);
weightMap.put(server, weight);
}
}
@Override
public String chooseServer() {
int weightSum = weightMap.values().stream().reduce(Integer::sum).orElse(0);
int randomWeight = ThreadLocalRandom.current().nextInt(weightSum) + 1;
for (String server : servers) {
int weight = weightMap.get(server);
if (randomWeight <= weight) {
return server;
}
randomWeight -= weight;
}
return null;
}
}
4 源地址哈希法 (Hash)
源地址哈希法是一種基于客戶端 IP 地址的負載均衡算法,通過哈希函數將客戶端IP映射到特定的服務器,確保來自同一IP的請求總是被轉發到同一臺服務器。

示例代碼:
import java.util.List;
import java.util.zip.CRC32;
public class SourceIPHashLoadBalancer {
private final List<String> servers;
public SourceIPHashLoadBalancer(List<String> servers) {
this.servers = servers;
}
public String getServer(String clientIP) {
if (servers.isEmpty()) {
return null;
}
// 計算IP的哈希值
long hash = calculateHash(clientIP);
// 取模確定服務器索引
int index = (int) (hash % servers.size());
return servers.get(Math.abs(index));
}
private long calculateHash(String ip) {
CRC32 crc32 = new CRC32();
crc32.update(ip.getBytes());
return crc32.getValue();
}
}
5 最少連接 (Least Connections)
最少連接算法是一種動態負載均衡策略,它會將新請求分配給當前連接數最少的服務器,以實現更均衡的服務器負載分配。

它的特點是:
- 實時監控:跟蹤每臺服務器的活躍連接數
- 動態決策:新請求總是分配給當前連接數最少的服務器
- 自適應:自動適應不同請求處理能力的服務器
示例代碼:
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class LeastConnectionsLoadBalancer {
private final List<String> servers;
private final ConcurrentHashMap<String, AtomicInteger> connectionCounts;
public LeastConnectionsLoadBalancer(List<String> servers) {
this.servers = servers;
this.connectionCounts = new ConcurrentHashMap<>();
servers.forEach(server -> connectionCounts.put(server, new AtomicInteger(0)));
}
public String getServer() {
if (servers.isEmpty()) {
return null;
}
// 找出連接數最少的服務器
String selectedServer = servers.get(0);
int minConnections = connectionCounts.get(selectedServer).get();
for (String server : servers) {
int currentConnections = connectionCounts.get(server).get();
if (currentConnections < minConnections) {
minConnections = currentConnections;
selectedServer = server;
}
}
// 增加選中服務器的連接數
connectionCounts.get(selectedServer).incrementAndGet();
return selectedServer;
}
public void releaseConnection(String server) {
connectionCounts.get(server).decrementAndGet();
}
}
6 最快響應時間 (Least Response Time)
最快響應時間(Least Response Time,LRT)是一種智能動態負載均衡算法,它通過選擇當前響應時間最短的服務器來處理新請求,從而優化整體系統性能。

LRT 算法基于以下核心判斷標準:
- 實時性能監控:持續跟蹤每臺服務器的歷史響應時間
- 動態路由決策:新請求總是分配給響應最快的可用服務器
- 自適應學習:根據服務器性能變化自動調整流量分配
示例代碼:
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class LeastResponseTimeLoadBalancer {
private final List<String> servers;
private final ConcurrentHashMap<String, ResponseTimeStats> serverStats;
// 響應時間統計結構
static class ResponseTimeStats {
private final AtomicInteger totalRequests = new AtomicInteger(0);
private final AtomicLong totalResponseTime = new AtomicLong(0);
private volatile boolean isHealthy = true;
public void recordResponseTime(long responseTimeMs) {
totalRequests.incrementAndGet();
totalResponseTime.addAndGet(responseTimeMs);
}
public double getAverageResponseTime() {
int requests = totalRequests.get();
return requests == 0 ? 0 : (double)totalResponseTime.get() / requests;
}
}
public LeastResponseTimeLoadBalancer(List<String> servers) {
this.servers = new CopyOnWriteArrayList<>(servers);
this.serverStats = new ConcurrentHashMap<>();
servers.forEach(server -> serverStats.put(server, new ResponseTimeStats()));
}
public String getServer() {
if (servers.isEmpty()) return null;
return servers.stream()
.filter(server -> serverStats.get(server).isHealthy)
.min(Comparator.comparingDouble(server ->
serverStats.get(server).getAverageResponseTime()))
.orElse(null);
}
public void updateResponseTime(String server, long responseTimeMs) {
ResponseTimeStats stats = serverStats.get(server);
if (stats != null) {
stats.recordResponseTime(responseTimeMs);
}
}
public void markServerDown(String server) {
ResponseTimeStats stats = serverStats.get(server);
if (stats != null) stats.isHealthy = false;
}
public void markServerUp(String server) {
ResponseTimeStats stats = serverStats.get(server);
if (stats != null) stats.isHealthy = true;
}
}
浙公網安備 33010602011771號