> 技术文档 > 负载均衡、算法/策略

负载均衡、算法/策略


负载均衡


一、负载均衡层级对比

特性 四层负载均衡 (L4) 七层负载均衡 (L7) 工作层级 传输层 (TCP/UDP) 应用层 (HTTP/HTTPS等) 决策依据 源/目标IP+端口 URL路径、Header、Cookie、内容等 转发方式 IP地址/端口替换 重建连接并深度解析报文 性能 更高吞吐量,更低延迟 需内容解析,性能略低于L4 典型工具 LVS、F5(硬件)、Nginx(TCP/UDP模式) Nginx、HAProxy、Apache 场景案例 数据库负载、游戏服务器 动静分离、灰度发布、WAF防护

二、负载均衡核心算法解析

算法类型 原理 适用场景 轮询 (RR) 请求按序分配至所有服务器 服务器性能均等的静态资源 加权轮询 (WRR) 按服务器权重分配请求 异构服务器集群(如GPU/CPU机型混合) 最小连接数 (LC) 优先选择当前连接数最少的服务器 长连接服务(数据库、WebSocket) 响应时间 (RT) 基于健康检查的响应时间决策 对延迟敏感的服务(实时交易系统) IP Hash 同一客户端IP固定路由到相同服务器 会话保持需求(如未共享Session的服务) URL Hash 相同URL请求路由到固定服务器 缓存优化场景 一致性哈希 服务器增减时仅影响少量请求分布 分布式缓存/数据库集群

三、关键工具能力矩阵

功能 Nginx HAProxy LVS 四层代理 ✅ (Stream模块) ✅ ✅(内核级) 七层代理 ✅ (HTTP模块) ✅ ❌ 动态路由规则 🔶 (正则匹配) ✅ (ACL高级规则) ❌ 会话保持 🔶 (IP Hash) ✅ (多种策略) ✅ (持久化连接) 健康检查 ✅ ✅ (多协议) ✅ SSL卸载 ✅ ✅ ❌ 典型部署位置 边缘入口/应用层 TCP/HTTP层 网络层

四、分层负载均衡工作流对比

四层负载均衡 (LVS为例)

#mermaid-svg-xVA7EqGHpxIUQ6WQ {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .error-icon{fill:#552222;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .marker.cross{stroke:#333333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .cluster-label text{fill:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .cluster-label span{color:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .label text,#mermaid-svg-xVA7EqGHpxIUQ6WQ span{fill:#333;color:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .node rect,#mermaid-svg-xVA7EqGHpxIUQ6WQ .node circle,#mermaid-svg-xVA7EqGHpxIUQ6WQ .node ellipse,#mermaid-svg-xVA7EqGHpxIUQ6WQ .node polygon,#mermaid-svg-xVA7EqGHpxIUQ6WQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .node .label{text-align:center;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .node.clickable{cursor:pointer;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .arrowheadPath{fill:#333333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .cluster text{fill:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ .cluster span{color:#333;}#mermaid-svg-xVA7EqGHpxIUQ6WQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xVA7EqGHpxIUQ6WQ :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}SYN修改目标IP为后端SYN-ACKHTTP请求仅转发IP包ClientLVSServer1

📌 核心动作:IP地址转换(DNAT),无TCP连接代理。

七层负载均衡 (Nginx为例)

#mermaid-svg-KrZNLLqJro7yli6n {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KrZNLLqJro7yli6n .error-icon{fill:#552222;}#mermaid-svg-KrZNLLqJro7yli6n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KrZNLLqJro7yli6n .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-KrZNLLqJro7yli6n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KrZNLLqJro7yli6n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KrZNLLqJro7yli6n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KrZNLLqJro7yli6n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KrZNLLqJro7yli6n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KrZNLLqJro7yli6n .marker.cross{stroke:#333333;}#mermaid-svg-KrZNLLqJro7yli6n svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KrZNLLqJro7yli6n .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KrZNLLqJro7yli6n .cluster-label text{fill:#333;}#mermaid-svg-KrZNLLqJro7yli6n .cluster-label span{color:#333;}#mermaid-svg-KrZNLLqJro7yli6n .label text,#mermaid-svg-KrZNLLqJro7yli6n span{fill:#333;color:#333;}#mermaid-svg-KrZNLLqJro7yli6n .node rect,#mermaid-svg-KrZNLLqJro7yli6n .node circle,#mermaid-svg-KrZNLLqJro7yli6n .node ellipse,#mermaid-svg-KrZNLLqJro7yli6n .node polygon,#mermaid-svg-KrZNLLqJro7yli6n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KrZNLLqJro7yli6n .node .label{text-align:center;}#mermaid-svg-KrZNLLqJro7yli6n .node.clickable{cursor:pointer;}#mermaid-svg-KrZNLLqJro7yli6n .arrowheadPath{fill:#333333;}#mermaid-svg-KrZNLLqJro7yli6n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KrZNLLqJro7yli6n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KrZNLLqJro7yli6n .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-KrZNLLqJro7yli6n .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-KrZNLLqJro7yli6n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KrZNLLqJro7yli6n .cluster text{fill:#333;}#mermaid-svg-KrZNLLqJro7yli6n .cluster span{color:#333;}#mermaid-svg-KrZNLLqJro7yli6n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KrZNLLqJro7yli6n :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}TCP握手新建连接至后端全量数据处理解析/修改HTTP内容ClientNginxServer1

📌 核心动作: 双向TCP代理 + 应用层解析(可修改Header/压缩内容)。


五、典型场景技术选型建议

  1. 静态资源加速
    → ​Nginx​(七层路由: location /images/ { proxy_pass img_server; } + 缓存)
  2. 微服务API网关
    → ​HAProxy​(精确流量控制:基于Path/Header路由到K8s Pod)
  3. 数据库读写分离
    → ​LVS​(四层IP转发) + ​MaxScale​(七层SQL解析)
  4. 全局负载均衡 (GSLB)
    → ​DNS智能解析​(基于地理位置的IP响应)

六、前沿趋势补充

  • Service Mesh架构:Envoy等Sidecar代理实现细粒度L7流量管理
  • eBPF技术:Cilium实现内核级四层负载,绕过iptables提升性能
  • 云原生负载均衡:AWS ALB/NLB、GCP Cloud Load Balancing的自动化策略

😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉 😌 😍 🤩 🥰 😘 😗 😙 😋 😛 🤩 🥳 😏 😒 😞 😔 😟 😕 🙁 😠 😤 😭

负载均衡算法/策略

一、基础轮询算法(Round Robin)

场景:适用于服务器集群配置均衡的无状态服务
Java实现​:

public class RoundRobinBalancer { private List<String> servers = new ArrayList<>(); private AtomicInteger currentIndex = new AtomicInteger(0); public RoundRobinBalancer(List<String> servers) { this.servers = new ArrayList<>(servers); } public String nextServer() { if(servers.isEmpty()) throw new IllegalStateException(\"No servers available\"); int index = currentIndex.getAndUpdate( i -> (i + 1) % servers.size() ); return servers.get(index); }}// 使用示例List<String> backendServers = Arrays.asList(\"192.168.1.1\", \"192.168.1.2\", \"192.168.1.3\");RoundRobinBalancer balancer = new RoundRobinBalancer(backendServers);// 模拟10次请求for(int i=0; i<10; i++) { String server = balancer.nextServer(); System.out.println(\"Request \" + i + \" -> \" + server);}

输出规律

Request 0 -> 192.168.1.1Request 1 -> 192.168.1.2Request 2 -> 192.168.1.3Request 3 -> 192.168.1.1Request 4 -> 192.168.1.2... // 持续循环

二、加权轮询算法(Weighted Round Robin)

场景:服务器性能不均衡场景(如3台服务器配置比为 3:2:1)
Java实现​:

public class WeightedRoundRobin { static class Server { String address; int weight; int currentWeight; // 动态权重值 public Server(String address, int weight) { this.address = address; this.weight = weight; this.currentWeight = weight; // 初始化为固定权重 } } private final List<Server> servers = new ArrayList<>(); private final AtomicInteger lock = new AtomicInteger(0); public void addServer(String address, int weight) { servers.add(new Server(address, weight)); } public String nextServer() { if (servers.isEmpty()) return null; Server selected = null; int total = 0; // 原子操作保证线程安全 synchronized (lock) { // 1. 遍历所有服务器增加权重 for (Server server : servers) { server.currentWeight += server.weight; total += server.weight; // 2. 选择当前权重最高者 if (selected == null || server.currentWeight > selected.currentWeight) {  selected = server; } } // 3. 减少选中服务器的权重 if (selected != null) { selected.currentWeight -= total; } } return selected.address; }}// 使用示例WeightedRoundRobin wrr = new WeightedRoundRobin();wrr.addServer(\"192.168.1.1\", 3); // 高性能服务器wrr.addServer(\"192.168.1.2\", 2); // 中等性能wrr.addServer(\"192.168.1.3\", 1); // 低性能// 请求分布统计Map<String, Integer> counter = new HashMap<>();for(int i=0; i<600; i++) { String server = wrr.nextServer(); counter.put(server, counter.getOrDefault(server, 0) + 1);}System.out.println(\"流量分布: \" + counter);

输出示例

流量分布: {192.168.1.1=300, 192.168.1.2=200, 192.168.1.3=100} // 符合3:2:1比例

三、最少连接数算法(Least Connections)

场景:长连接服务(数据库连接、文件传输)
Java实现​:

public class LeastConnectionBalancer { static class ServerState { String address; AtomicInteger connectionCount = new AtomicInteger(0); } private final PriorityQueue<ServerState> queue = new PriorityQueue<>(Comparator.comparingInt(s -> s.connectionCount.get())); public synchronized void addServer(String address) { queue.add(new ServerState(address)); } // 请求时增加连接计数 public synchronized String acquireServer() { if (queue.isEmpty()) return null; ServerState server = queue.peek(); server.connectionCount.incrementAndGet(); return server.address; } // 请求完成后释放连接 public synchronized void releaseServer(String address) { queue.stream() .filter(s -> s.address.equals(address)) .findFirst() .ifPresent(s -> s.connectionCount.decrementAndGet()); } // 获取当前最空闲服务器 public synchronized String getIdleServer() { if (queue.isEmpty()) return null; return queue.peek().address; }}// 使用示例LeastConnectionBalancer lc = new LeastConnectionBalancer();lc.addServer(\"192.168.1.1\");lc.addServer(\"192.168.1.2\");// 模拟连接使用String server1 = lc.acquireServer(); // 192.168.1.1 (连接数=1)String server2 = lc.acquireServer(); // 192.168.1.2 (连接数=1)String server3 = lc.acquireServer(); // 192.168.1.1 (连接数=2)String server4 = lc.acquireServer(); // 192.168.1.2 (连接数=2)lc.releaseServer(server1); // 释放192.168.1.1的连接String nextServer = lc.getIdleServer(); // 返回192.168.1.1

四、一致性哈希算法(Consistent Hashing)

场景:分布式缓存、会话保持
Java实现​:

public class ConsistentHashRouter { // 虚拟节点环结构 private final TreeMap<Integer, String> ring = new TreeMap<>(); private final int virtualReplicas; // 虚拟节点数 public ConsistentHashRouter(List<String> servers, int virtualReplicas) { this.virtualReplicas = virtualReplicas; for (String server : servers) { addServer(server); } } public void addServer(String server) { // 每个物理节点创建多个虚拟节点 for (int i = 0; i < virtualReplicas; i++) { String virtualNode = server + \"#\" + i; int hash = Math.abs(virtualNode.hashCode()); ring.put(hash, server); } } public void removeServer(String server) { // 移除所有关联虚拟节点 for (int i = 0; i < virtualReplicas; i++) { String virtualNode = server + \"#\" + i; int hash = Math.abs(virtualNode.hashCode()); ring.remove(hash); } } public String routeTo(String requestKey) { if (ring.isEmpty()) return null; int hash = Math.abs(requestKey.hashCode()); // 找到大于等于该哈希值的第一个节点 Map.Entry<Integer, String> entry = ring.ceilingEntry(hash); // 环回处理:找不到时选择首节点 if (entry == null) { entry = ring.firstEntry(); } return entry.getValue(); }}// 测试扩容容错性List<String> initialServers = Arrays.asList(\"S1\", \"S2\", \"S3\");ConsistentHashRouter router = new ConsistentHashRouter(initialServers, 200);// 统计1000个键的分布Map<String, Integer> distribution = new HashMap<>();for(int i=0; i<1000; i++) { String key = \"req-\" + i; String server = router.routeTo(key); distribution.put(server, distribution.getOrDefault(server, 0) + 1);}System.out.println(\"初始分布: \" + distribution);// 移除S1节点router.removeServer(\"S1\");// 重新统计相同键的路由Map<String, Integer> newDistribution = new HashMap<>();for(int i=0; i<1000; i++) { String key = \"req-\" + i; String server = router.routeTo(key); newDistribution.put(server, newDistribution.getOrDefault(server, 0) + 1);}System.out.println(\"移除S1后分布: \" + newDistribution);

关键输出

初始分布: {S1=328, S2=345, S3=327}移除S1后分布: {S2=487, S3=513} // 仅有32%的请求被迁移

五、响应时间算法(Response Time Based)

场景:对延迟敏感的服务(金融交易系统)
Java实现​:

public class ResponseTimeBalancer { static class ServerProfile { String address; double ewmaResponseTime = 100.0; // 指数加权平均 AtomicInteger inflightRequests = new AtomicInteger(0); } private final List<ServerProfile> servers = new CopyOnWriteArrayList<>(); private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public ResponseTimeBalancer(List<String> addresses) { for(String addr : addresses) { servers.add(new ServerProfile(addr)); } // 启动实时健康检查 scheduler.scheduleAtFixedRate(this::updateResponseTimes, 1, 1, TimeUnit.SECONDS); } private void updateResponseTimes() { for(ServerProfile server : servers) { // 模拟探测请求 long start = System.currentTimeMillis(); boolean reachable = pingServer(server.address); long rt = System.currentTimeMillis() - start; // 更新EWMA响应时间 (α=0.3) if(reachable) { double newRt = server.ewmaResponseTime * 0.7 + rt * 0.3; server.ewmaResponseTime = newRt; } else { server.ewmaResponseTime = Double.MAX_VALUE; // 标记为不可用 } } } public String getOptimalServer() { return servers.stream() .filter(s -> s.inflightRequests.get() < 100) // 流量控制 .min(Comparator.comparingDouble(s ->  s.ewmaResponseTime + 0.5 * s.inflightRequests.get())) .map(s -> { s.inflightRequests.incrementAndGet(); return s.address; }) .orElse(null); } public void completeRequest(String address) { servers.stream() .filter(s -> s.address.equals(address)) .findFirst() .ifPresent(s -> s.inflightRequests.decrementAndGet()); } private boolean pingServer(String address) { // 实际实现需包含TCP连接测试或HTTP GET return Math.random() > 0.02; // 模拟98%可用率 }}

算法公式
Score = EWMA_RT + β * Inflight_Requests
其中:

  • EWMA_RT:指数加权移动平均响应时间
  • Inflight_Requests:当前正在处理的请求数
  • β:可调节参数(建议0.3-0.7)

六、动态权重调整(生产级方案)

graph TD A[客户端] -->|公共DNS| B(全局GSLB) B --> C[区域LB集群(Nginx L7)] C -->|用户会话| D[应用服务器集群] C -->|静态资源| E[CDN边缘节点] D --> F[微服务网关] F --> G[服务注册中心] G -->|服务发现| H[业务微服务] G -->|连接池管理| I[数据库代理]
算法选择决策树
 +-----------------+ | 需要会话保持? | +-------+---------+ |  +-----------------------+-----------------+  |  | 是  否  |  |+-------------v-----------+ +--------------v-------------+| 请求特征固定?  | | 后端服务器性能差异>30%? |+-------------+-----------+ +--------------+-------------+  |  | +-------v-------+  +---------v---------+ | 是 --> 哈希 |  | 是 --> 权重轮询 | +-+-+----------+  +---------+---------+ | | | | +-----------------+  | |  |  |+-------v--------+ +--------v-------+ +-------v--------+| URL有规律 ? | | IP固定? | | 否 --> 标准轮询 |+-------+--------+ +-------+--------+ +----------------+ |  | +----v----+ +-----v------+ | URL哈希 | | IP哈希 | +---------+ +------------+

结合服务器实时指标动态计算权重:

public class DynamicWeightCalculator { private final Map<String, Double> weights = new ConcurrentHashMap<>(); private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); public void startMonitoring(List<String> servers) { executor.scheduleAtFixedRate(() -> { for (String server : servers) { double newWeight = calculateCurrentWeight(server); weights.put(server, newWeight); } }, 0, 10, TimeUnit.SECONDS); // 每10秒更新 } private double calculateCurrentWeight(String server) { // 获取服务器指标(实际需调用监控系统API) double cpu = getCpuUsage(server); double memory = getMemoryUsage(server); int connections = getCurrentConnections(server); // 权重计算公式 double baseWeight = 100.0; // 基础权重 double stabilityFactor = 1.0 / (1 + Math.exp(cpu - 85)); // CPU过载惩罚 double weight = baseWeight * stabilityFactor / (1 + 0.1 * connections); return Math.max(weight, 5.0); // 不低于最小权重 } // 在加权路由器中调用 public double getCurrentWeight(String server) { return weights.getOrDefault(server, 1.0); }}// 集成到加权轮询public class DynamicWeightedBalancer extends WeightedRoundRobin { private final DynamicWeightCalculator weightCalculator; public DynamicWeightedBalancer(DynamicWeightCalculator calculator) { this.weightCalculator = calculator; } @Override public String nextServer() { // 每次请求前动态设置权重 for(Server server : servers) { double newWeight = weightCalculator.getCurrentWeight(server.address); server.weight = (int) newWeight; } return super.nextServer(); }}

七、策略选择建议

场景特征 推荐算法 Java实现要点 无状态服务+服务器均等 轮询 (RR) 原子计数器循环 服务器性能差异>30% 加权轮询 (WRR) 平滑权重分配算法 长连接服务 (FTP/数据库) 最少连接数 (LC) 优先级队列+连接计数 会话保持需求 一致性哈希 TreeMap虚拟节点环 延迟敏感 (RT<50ms) 响应时间优先 EWMA实时计算+探测请求 服务器状态波动大 动态权重 定时指标获取+权重公式

性能关键

  1. 使用AtomicInteger替代synchronized减少锁竞争
  2. 虚拟节点数至少设置为物理节点的100-200倍
  3. 实时指标通过独立线程池批量获取(避免阻塞请求线程)
  4. 过期服务器通过心跳检测自动摘除