2. 负载均衡基础:概念、作用与常用算法
说起负载均衡,很多刚入行的朋友第一反应是“这不就是个反向代理嘛,配个轮询就完事了”。嗯,这么说也对,但只说对了一半。我自己的经验是,负载均衡是整个服务稳定性的底盘,选错了算法,后面加再多节点也没用。
说白了,负载均衡就是把你收到的请求,按照某种策略分发给后端的多个服务器。客户不会直接访问你的业务节点,而是先打到负载均衡器上,由它来决定“这活交给谁干”。
2.1 为什么要做负载均衡?
想想看,如果只有一个后端节点,它挂了怎么办?流量高峰来了压力全压它身上,响应慢了用户投诉,CPU 满了直接 OOM。你肯定不希望这样。
负载均衡解决的核心问题有三个:
- 高可用 —— 一台挂了,流量切到其他节点,服务不中断。我在项目中见过因 MySQL 主库扛不住而切备机,但前端负载均衡没配好,备机没流量,用户全超时。血的教训。
- 水平扩展 —— 加机器就能扛更多请求,不用改动业务代码。只要你把新节点注册到 LVS 或 Nginx 上游列表里就行。
- 故障隔离 —— 负载均衡器配合健康检查,能自动摘掉有问题的节点。我曾经没配超时检测,一台服务器 Java 进程假死,负载均衡还在往它那发请求,结果部分用户永远在转圈。
2.2 负载均衡器的分类
你可能听过四层和七层的说法。我简单解释一下:
| 类型 | 工作层级 | 常见实例 | 适用场景 |
|---|---|---|---|
| 四层(L4) | 传输层(IP+端口) | LVS、F5、HAProxy(TCP模式) | 高吞吐、低延迟,如数据库、游戏服务 |
| 七层(L7) | 应用层(HTTP/HTTPS) | Nginx、HAProxy(HTTP模式)、Traefik | 需要根据域名、URL、Cookie 做分发,如 Web API |
| DNS 轮询 | 应用层(域名解析) | DNS A 记录多值 | 全局 GSLB,简单但无法感知后端健康 |
咱们加密服务通常走七层,因为要终止 TLS、根据 SNI 域名做分发。四层适合纯 TCP 透传,比如数据库连接池。
2.3 常用负载均衡算法
算法是负载均衡的灵魂。我亲眼见过因为选了“轮询”导致 CPU 不均衡的案例——后端机器配置不一样,新的机器性能强却只分到和旧机器一样多的请求。下面我把常用算法列出来,你对比看看。
2.3.1 轮询(Round Robin)
最简单。请求按顺序轮流分配给后端。没有权重,一视同仁。
# Nginx 上游配置
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
特点:实现简单,开销小。但如果有慢请求积压,会引发“队头阻塞”。我建议只用在后端机器配置完全一致的场景。
2.3.2 加权轮询(Weighted Round Robin)
给每个节点配个 weight,比如新机器 weight=3,旧机器 weight=1,新机器拿到的请求数是旧机器的 3 倍。
upstream backend {
server 10.0.0.1:8080 weight=3;
server 10.0.0.2:8080 weight=1;
}
注意:加权轮询只是“概率均匀”,不保证严格比例。如果你的客户端长连接很多,用加权最小连接更合适。
2.3.3 最少连接(Least Connections)
负载均衡器记录每个节点当前的活跃连接数,每次把新请求发给连接数最少的那个。
upstream backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}
适用场景:请求处理时间差异大时效果最好。比如有的请求查缓存快,有的查慢查询慢。我在做图片处理服务时就用的 least_conn,因为图片大小差很多,轮询会导致性能差的那台堆满连接。
2.3.4 IP 哈希(IP Hash)
根据客户端的 IP 地址计算哈希,把同一来源的请求始终发给同一个后端。
upstream backend {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}
为什么要用它? 最常见的场景是会话粘性——用户登录状态保存在本机 Session 里,如果下次请求跳到别的机器,Session 丢了,用户得重新登录。IP hash 能保证同一 IP 永远落在同一节点。不过要注意:如果客户端使用了 NAT 或 IPv6 前缀,hash 可能会不均。我在某电商平台就遇见过,公司出口 IP 只有几个,所有内部员工都挤到同一台机器上去了……
2.3.5 一致性哈希(Consistent Hashing)
这是 IP hash 的升级版。当后端节点增减时,只有少部分请求会被重新映射,不会像 IP hash 那样导致大量 Session 漂移。常用于缓存集群(比如 Redis、Memcached)的负载均衡。
# Nginx 通过 ngx_http_upstream_consistent_hash 模块
upstream backend {
consistent_hash $request_uri;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
对比一下四种主要算法:
| 算法 | 平衡性 | 带权支持 | 会话保持 | 节点增减影响 | 典型场景 |
|---|---|---|---|---|---|
| 轮询 | 好(配置相同) | 支持加权 | 否 | 无影响 | 无状态 API |
| 最少连接 | 最好(请求时长不等) | 支持加权 | 否 | 无影响 | 长连接、耗时差异大 |
| IP 哈希 | 中等(取决于 IP 分布) | 一般不支持 | 是 | 影响大 | 有状态会话 |
| 一致性哈希 | 较好 | 可扩展 | 是 | 影响小 | 缓存集群、分布式存储 |
2.4 如何选择算法?
没有银弹。我个人的做法是:先看业务状态。
- 如果是加密服务(SSL 卸载、证书管理),请求基本无状态,轮询或最少连接都行。但要注意 TLS 握手有 CPU 消耗,最少连接能更均衡。
- 如果后端需要保持会话(比如用户登录后的 Session),用 IP hash 加一层 Redis Session 共享更靠谱。我以前踩过坑——只用 IP hash,结果运维一扩缩容节点,哈希打乱,session 全跑调了。后来改了一致性哈希才稳住。
- 后端机器配置不同时,加权轮询或加权最少连接是必须的,否则所有流量往弱鸡服务器上灌就等于自杀。
2.5 负载均衡与健康检查的关系
光有均衡算法还不够。你想想看,一个节点已经挂了,负载均衡器还傻傻地往它那发请求,算法再好也没用。这时候就得靠健康检查来保命了。
负载均衡器周期性向后端节点发送探测请求(TCP 端口探活、HTTP 状态码检查、甚至自定义脚本),根据返回值判断节点状态。一旦发现节点异常,自动把它从上游列表中摘掉,不再分配新请求。等恢复正常后,再自动加回来。
健康检查的时机、间隔、超时、重试次数,每个参数都会影响系统稳定性。这部分我们下一章会细讲。
下面我用一张流程图把核心概念串起来 —— 从客户端请求到负载均衡器选择算法,再到健康检查的动态剔除与恢复。
从这张图你也能看出来,负载均衡器和健康检查是双胞胎,谁也离不开谁。算法决定“怎么分”,健康检查决定“分给谁”。下一章我们会深入健康检查的具体实现和参数调优,这里先留个印象。
2.6 小结
这一章我们聊了负载均衡的定义、为什么需要它、四层七层的区别,以及五种常用算法的原理和适用场景。我特别强调了一句:算法没有好坏,关键看你的后端服务有没有状态、机器配置是否一致、请求处理时间是否均匀。嗯,记住这两点,你在设计加密服务负载均衡方案时就能少走很多弯路。