负载均衡、算法/策略
负载均衡
一、负载均衡层级对比
二、负载均衡核心算法解析
三、关键工具能力矩阵
四、分层负载均衡工作流对比
四层负载均衡 (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/压缩内容)。
五、典型场景技术选型建议
- 静态资源加速
→ Nginx(七层路由:location /images/ { proxy_pass img_server; }
+ 缓存) - 微服务API网关
→ HAProxy(精确流量控制:基于Path/Header路由到K8s Pod) - 数据库读写分离
→ LVS(四层IP转发) + MaxScale(七层SQL解析) - 全局负载均衡 (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(); }}
七、策略选择建议
性能关键:
- 使用
AtomicInteger
替代synchronized
减少锁竞争 - 虚拟节点数至少设置为物理节点的100-200倍
- 实时指标通过独立线程池批量获取(避免阻塞请求线程)
- 过期服务器通过心跳检测自动摘除