六种负载均衡算法
Salted Fish 2025/11/12 算法
负载均衡(Load Balancing)是一种计算机网络和服务器管理技术,旨在分配网络流量、请求或工作负载到多个服务器或资源,以确保这些服务器能够高效、均匀地处理负载,并且能够提供更高的性能、可用性和可扩展性。
# 1. 轮询 (Round Robin)
轮询算法将请求按顺序分配给每个服务器,就像循环队列一样。第一个请求分配给第一个服务器,第二个请求分配给第二个服务器,直到所有服务器都分配到了请求,然后再次从第一个服务器开始。

适用场景
- 所有服务器硬件配置相同
- 每个请求的处理时间差不多
- 不需要保持会话状态
优缺点
- 优点:简单、公平
- 缺点:不考虑服务器性能差异和当前负载
# Nginx实现
http {
upstream backend {
# 默认就是轮询,无需特殊指令
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 代码实现
public class RoundRobinLoadBalancer {
private List<String> servers;
private AtomicInteger currentIndex = new AtomicInteger(0);
public RoundRobinLoadBalancer(List<String> servers) {
this.servers = servers;
}
public String getServer() {
int index = currentIndex.getAndIncrement() % servers.size();
if (index < 0) {
index = Math.abs(index);
}
return servers.get(index);
}
}
// 使用示例
List<String> servers = Arrays.asList("server1:8080", "server2:8080", "server3:8080");
RoundRobinLoadBalancer lb = new RoundRobinLoadBalancer(servers);
// 每次调用轮换服务器
String selectedServer = lb.getServer();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 2. 粘性轮询 (Sticky Round-Robin)
粘性轮询是标准轮询算法的一个变种,它通过记住客户端与服务实例的映射关系,确保来自同一客户端的连续请求会被路由到同一个服务实例上。

特点
- 会话保持:一旦客户端首次请求被分配到某个服务实例,后续请求会"粘"在这个实例上
- 客户端识别:通常基于客户端IP、会话ID或特定HTTP头来识别客户端
- 故障转移:当目标服务实例不可用时,系统会重新分配客户端到其他可用实例
适用场景
- 需要会话保持(session affinity)的应用,比如购物车、用户登录状态等。
- 文件上传等需要连续连接的业务
# Nginx实现
upstream backend {
# 基于IP的粘性会话
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 或者基于cookie
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
server {
listen 80;
location / {
# 基于cookie的粘性会话
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 添加cookie用于会话保持
proxy_cookie_path / "/; sticky";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 代码实现
@Configuration
public class LoadBalancerConfig {
@Bean
public ServiceInstanceListSupplier stickySessionSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withBlockingDiscoveryClient()
.withCaching()
.withStickySessions() // 启用粘性会话
.build(context);
}
}
// 或者在代码中手动实现
@Component
public class StickySessionLoadBalancer {
private final List<String> servers = Arrays.asList("server1", "server2", "server3");
private final Map<String, String> sessionMap = new ConcurrentHashMap<>();
public String getServer(String sessionId) {
return sessionMap.computeIfAbsent(sessionId,
key -> servers.get(Math.abs(key.hashCode()) % servers.size()));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 3. 加权轮询 (Weighted Round-Robin)
加权轮询是标准轮询算法的增强版本,它允许管理员为每个服务实例分配不同的权重值。权重越高的实例处理越多的请求,从而实现更精细的负载分配。

特点
权重分配:每个服务实例都有对应的权重值
比例分配:请求按权重比例分配到不同实例
动态调整:权重可以动态修改以适应不同场景
适用场景
- 服务器配置不均,希望性能好的服务器处理更多请求。
# Nginx实现
upstream backend {
server 192.168.1.10:8080 weight=5; # 高性能服务器
server 192.168.1.11:8080 weight=3; # 中等性能
server 192.168.1.12:8080 weight=1; # 低性能服务器
server 192.168.1.13:8080 weight=0; # 备份服务器,不参与负载
}
1
2
3
4
5
6
2
3
4
5
6
# 代码实现(平滑加权轮询算法)
public class WeightedRoundRobinLoadBalancer {
private List<Server> servers;
static class Server {
String address;
int weight; // 配置权重
int currentWeight; // 当前权重
public Server(String address, int weight) {
this.address = address;
this.weight = weight;
this.currentWeight = 0;
}
}
public WeightedRoundRobinLoadBalancer(Map<String, Integer> serverWeights) {
this.servers = new ArrayList<>();
serverWeights.forEach((address, weight) -> {
servers.add(new Server(address, weight));
});
}
public String getServer() {
// 选择当前权重最大的服务器
Server selected = null;
int totalWeight = 0;
for (Server server : servers) {
server.currentWeight += server.weight;
totalWeight += server.weight;
if (selected == null || server.currentWeight > selected.currentWeight) {
selected = server;
}
}
if (selected != null) {
selected.currentWeight -= totalWeight;
return selected.address;
}
return null;
}
}
// 使用示例
Map<String, Integer> serverWeights = new HashMap<>();
serverWeights.put("server1:8080", 5);
serverWeights.put("server2:8080", 3);
serverWeights.put("server3:8080", 1);
WeightedRoundRobinLoadBalancer lb = new WeightedRoundRobinLoadBalancer(serverWeights);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 4. 源地址哈希法 (Hash)
对客户端的IP地址(或其他标识)进行哈希计算,然后根据哈希值选择服务器。这样可以保证同一个客户端的请求总是被分配到同一台服务器。

适用场景
- 需要会话保持,且不使用粘性轮询的场合。
- 希望将特定客户端的请求固定到同一台服务器。
# Nginx实现
upstream backend {
hash $remote_addr; # 基于客户端IP哈希
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
# 或者基于其他变量哈希
upstream backend {
hash $request_uri; # 基于请求URI哈希
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 代码实现
public class HashLoadBalancer {
private List<String> servers;
public HashLoadBalancer(List<String> servers) {
this.servers = servers;
}
public String getServer(String key) {
if (servers.isEmpty()) {
return null;
}
int hashCode = Math.abs(key.hashCode());
int index = hashCode % servers.size();
return servers.get(index);
}
// 一致性哈希实现(减少服务器变动时的影响)
public static class ConsistentHashLoadBalancer {
private final SortedMap<Integer, String> circle = new TreeMap<>();
private final int virtualNodes; // 虚拟节点数
public ConsistentHashLoadBalancer(List<String> servers, int virtualNodes) {
this.virtualNodes = virtualNodes;
for (String server : servers) {
addServer(server);
}
}
private void addServer(String server) {
for (int i = 0; i < virtualNodes; i++) {
String virtualNode = server + "#" + i;
int hash = getHash(virtualNode);
circle.put(hash, server);
}
}
public String getServer(String key) {
if (circle.isEmpty()) {
return null;
}
int hash = getHash(key);
SortedMap<Integer, String> tailMap = circle.tailMap(hash);
int nodeHash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
return circle.get(nodeHash);
}
private int getHash(String key) {
// 使用MD5哈希,也可以使用其他哈希算法
return Math.abs(key.hashCode());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 5. 最少连接 (Least Connections)
最少连接算法是一种动态负载均衡策略,它会将新请求分配给当前连接数最少的服务器,以实现更均衡的服务器负载分配。

特点
- 实时监控:跟踪每台服务器的活跃连接数
- 动态决策:新请求总是分配给当前连接数最少的服务器
- 自适应:自动适应不同请求处理能力的服务器
适用场景
- 长连接应用,例如数据库连接、实时通信等。
- 当服务器处理能力不同,但已经用权重调整了连接数分配时,可以使用加权最少连接。
# Nginx实现
upstream backend {
least_conn; # 最少连接算法
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
# 也可以结合权重
server 192.168.1.13:8080 weight=3;
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 代码实现
public class LeastConnectionsLoadBalancer {
private List<ServerStats> servers;
static class ServerStats {
String address;
AtomicInteger activeConnections = new AtomicInteger(0);
int weight; // 可选:加权最少连接
public ServerStats(String address, int weight) {
this.address = address;
this.weight = weight;
}
public double getScore() {
// 考虑权重的评分,权重越高,能承受的连接数越多
return (double) activeConnections.get() / weight;
}
}
public LeastConnectionsLoadBalancer(List<String> servers) {
this.servers = new ArrayList<>();
for (String server : servers) {
this.servers.add(new ServerStats(server, 1));
}
}
public String getServer() {
ServerStats selected = null;
double minScore = Double.MAX_VALUE;
for (ServerStats server : servers) {
double score = server.getScore();
if (score < minScore) {
minScore = score;
selected = server;
}
}
if (selected != null) {
selected.activeConnections.incrementAndGet();
return selected.address;
}
return null;
}
public void releaseConnection(String serverAddress) {
for (ServerStats server : servers) {
if (server.address.equals(serverAddress)) {
server.activeConnections.decrementAndGet();
break;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 6. 最快响应时间 (Least Response Time)
最快响应时间(Least Response Time,LRT)通过选择当前响应时间最短的服务器来处理新请求,从而优化整体系统性能。这需要负载均衡器记录每个服务器的历史响应时间。

LRT 算法基于以下核心判断标准:
- 实时性能监控:持续跟踪每台服务器的历史响应时间
- 动态路由决策:新请求总是分配给响应最快的可用服务器
- 自适应学习:根据服务器性能变化自动调整流量分配
适用场景
- 对响应时间敏感的应用。
- 服务器性能差异较大,且希望客户端总是连接到响应最快的服务器。
# Nginx Plus实现
upstream backend {
least_time last_byte; # 基于完整响应时间
# least_time header; # 基于首字节时间
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 代码实现
public class LeastResponseTimeLoadBalancer {
private List<ServerMetrics> servers;
private final double alpha; // 指数平滑系数
static class ServerMetrics {
String address;
AtomicLong totalRequests = new AtomicLong(0);
AtomicDouble averageResponseTime = new AtomicDouble(100.0); // 初始值
int weight;
public ServerMetrics(String address, int weight) {
this.address = address;
this.weight = weight;
}
public double getScore() {
// 响应时间越短,分数越低
return averageResponseTime.get() / weight;
}
public void updateResponseTime(long responseTime) {
long count = totalRequests.incrementAndGet();
double currentAvg = averageResponseTime.get();
double newAvg = currentAvg + (responseTime - currentAvg) / Math.min(count, 100);
averageResponseTime.set(newAvg);
}
}
public LeastResponseTimeLoadBalancer(List<String> servers, double alpha) {
this.alpha = alpha;
this.servers = new ArrayList<>();
for (String server : servers) {
this.servers.add(new ServerMetrics(server, 1));
}
}
public String getServer() {
ServerMetrics selected = null;
double bestScore = Double.MAX_VALUE;
for (ServerMetrics server : servers) {
double score = server.getScore();
if (score < bestScore) {
bestScore = score;
selected = server;
}
}
return selected != null ? selected.address : null;
}
public void recordResponseTime(String serverAddress, long responseTimeMs) {
for (ServerMetrics server : servers) {
if (server.address.equals(serverAddress)) {
server.updateResponseTime(responseTimeMs);
break;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 微服务架构中的客户端负载均衡
# Spring Cloud LoadBalancer配置
spring:
cloud:
loadbalancer:
enabled: true
nacos:
discovery:
server-addr: localhost:8848
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
// 配置不同的负载均衡策略
@Configuration
public class LoadBalancerConfiguration {
@Bean
@LoadBalancerClient(name = "user-service", configuration = CustomLoadBalancerConfig.class)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier() {
return new DiscoveryClientServiceInstanceListSupplier();
}
}
// 自定义负载均衡配置
public class CustomLoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> weightedLoadBalancer(
Environment environment, LoadBalancerClientFactory factory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new WeightedRoundRobinLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21