聊聊六种负载均衡算法

服务器 服务器产品
负载均衡(Load Balancing)是一种计算机网络和服务器管理技术,旨在分配网络流量、请求或工作负载到多个服务器或资源,以确保这些服务器能够高效、均匀地处理负载,并且能够提供更高的性能、可用性和可扩展性。

负载均衡(Load Balancing)是一种计算机网络和服务器管理技术,旨在分配网络流量、请求或工作负载到多个服务器或资源,以确保这些服务器能够高效、均匀地处理负载,并且能够提供更高的性能、可用性和可扩展性。

这篇文章,我们聊聊六种通用的负载均衡算法。

图片图片

1.轮询 (Round Robin)

轮询是指将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。

图片图片

示例代码:

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

publicclass RoundRobin {
    privatefinal List<String> servers;
    privatefinal 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;

publicclass StickyRoundRobin {
    privatefinal List<String> servers;
    privatefinal AtomicInteger index = new AtomicInteger(0);
    privatefinal 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<>();
//记录服务器权重总和
privatestaticint totalWeight = 0;

public static String weightRandom() {
    //获取服务器数量
    int serverCount = serverMap.size();
    //如果没有可用的服务器返回null
    if (serverCount == 0) {
        returnnull;
    }
    //在此处为避免多线程并发操作造成错误,在方法内部进行锁操作
    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
    returnnull;
}

publicclass 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;
        }
        returnnull;
    }
}

4.源地址哈希法 (Hash)

源地址哈希法是一种基于客户端 IP 地址的负载均衡算法,通过哈希函数将客户端IP映射到特定的服务器,确保来自同一IP的请求总是被转发到同一台服务器。

图片图片

示例代码:

import java.util.List;
import java.util.zip.CRC32;

publicclass SourceIPHashLoadBalancer {
    privatefinal List<String> servers;
    
    public SourceIPHashLoadBalancer(List<String> servers) {
        this.servers = servers;
    }
    
    public String getServer(String clientIP) {
        if (servers.isEmpty()) {
            returnnull;
        }
        
        // 计算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;

publicclass LeastConnectionsLoadBalancer {
    privatefinal List<String> servers;
    privatefinal 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()) {
            returnnull;
        }
        
        // 找出连接数最少的服务器
        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.*;

publicclass LeastResponseTimeLoadBalancer {
    privatefinal List<String> servers;
    privatefinal ConcurrentHashMap<String, ResponseTimeStats> serverStats;
    
    // 响应时间统计结构
    staticclass ResponseTimeStats {
        privatefinal AtomicInteger totalRequests = new AtomicInteger(0);
        privatefinal AtomicLong totalResponseTime = new AtomicLong(0);
        privatevolatileboolean 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()) returnnull;
        
        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;
    }
}


责任编辑:武晓燕 来源: 勇哥Java实战
相关推荐

2023-11-28 15:32:30

负载均衡算法

2024-12-12 08:22:03

负载均衡算法无状态

2023-11-02 14:21:06

2019-09-12 09:22:58

Nginx负载均衡服务器

2022-05-24 10:43:02

延时消息分布式MQ

2010-04-26 14:52:37

2023-09-06 13:58:01

负载均衡算法

2017-06-26 10:35:58

前端JavaScript继承方式

2025-04-14 08:10:00

负载均衡代码java

2009-02-11 09:46:00

ASON网络演进

2019-12-26 09:13:00

算法硬件软件

2019-01-17 10:58:52

JS异步编程前端

2024-11-20 15:24:49

2010-05-04 16:10:51

负载均衡算法

2023-03-30 13:32:51

负载均衡器HDFS

2011-06-07 09:36:18

2012-10-15 13:26:31

云计算架构

2016-01-15 17:36:29

云计算云应用

2025-07-11 00:51:55

2025-02-27 00:00:30

SpringJava方式
点赞
收藏

51CTO技术栈公众号