做负载均衡最怕的不是机器不够,而是“均衡”本身出了问题。
之前我在处理一个电商线上集群时,三台应用服务器配置一模一样,Haproxy用的还是默认的轮询,可监控面板上中间那台CPU已经冲到80%,另外两台只有30%。我一开始怀疑是Haproxy坏了,后来手动抓包才发现:轮询虽然把请求平均发给了三台机器,但有一个响应特别慢的第三方接口调用,总是在某一台机器上结束长连接,导致这台机器的连接被长时间占用。换用leastconn并适当调整超时参数后,集群负载肉眼可见地平了。
也是从那次开始,我把Haproxy的负载均衡算法当成一门正经功课去研究。Haproxy之所以在负载均衡领域坐稳“瑞士军刀”的位置,除了性能强、配置灵活,更关键的是它提供的算法覆盖了从四层到七层绝大多数的业务形态:轮询、最少连接、源地址哈希、URI哈希、随机、一致性哈希……每个算法都是一套调度哲学,用对了事半功倍,用错了容易把故障无限放大。
这篇就按我实际调研和线上验证过的顺序,把Haproxy负载均衡算法的原理、适用场景、配置姿势和踩坑记录完整整理一遍。
1. 算法在Haproxy中的定位:配置位置与调度边界
1.1 一条balance指令能出现在哪里
Haproxy的负载均衡算法不是写在代码里的固定逻辑,而是通过配置指令 balance 来声明。这条指令有三个可写的位置:defaults、listen、backend。它们的生效范围是逐层覆盖的:defaults 里写的算法是全局默认值,listen 或者 backend 里写了就覆盖默认值。
我见过不少新手把算法写进 frontend,然后用 default_backend 转发,发现怎么都不生效,其实就是没搞清楚配置层级。下面是一段常见写法:
haproxy复制defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s
balance roundrobin
backend web_servers
balance leastconn
server web1 192.168.1.10:8080 check
server web2 192.168.1.11:8080 check
上面的配置里,defaults 中的 roundrobin 是默认算法,但 backend web_servers 里显式声明了 leastconn,最终这组后端实际使用的是 leastconn。
另一个容易忽略的点:backend 里可以针对不同服务器组使用不同算法,这一点在把多个前端入口复用同一个后端集群时特别有用。比如管理后台入口需要会话保持,可以用 source;用户前台入口没有会话要求,可以用 roundrobin。两个 frontend 各自指向同一个 backend 时,算法是在 backend 上全局生效的,所以如果入口不同、算法要求也不同,最好拆成两个 backend。
1.2 四层与七层的算法分界线
Haproxy 有两种运行模式:mode tcp 和 mode http。四层模式下,Haproxy 只解析到 TCP 层,能看到的信息是源IP、目的IP、端口;七层模式下,Haproxy 可以解析 HTTP 协议,能看到 URI、Header、Cookie、请求参数等。这个差异直接决定了哪些算法可用。
我整理了一张常用算法的层级可用性表:
| 算法 | 四层(mode tcp) | 七层(mode http) | 核心调度依据 |
|---|---|---|---|
| roundrobin | 支持 | 支持 | 加权轮询 |
| static-rr | 支持 | 支持 | 静态加权轮询 |
| leastconn | 支持 | 支持 | 当前连接数/权重 |
| first | 支持 | 支持 | 按序号优先填满 |
| source | 支持 | 支持 | 源IP哈希 |
| uri | 不支持 | 支持 | 请求URI哈希 |
| url_param | 不支持 | 支持 | 请求参数哈希 |
| hdr | 不支持 | 支持 | 指定请求头哈希 |
| rdp-cookie | 支持 | 不支持 | RDP Cookie哈希 |
| random | 支持 | 支持 | 加权随机 |
如果你在 mode tcp 下配置了 balance uri,Haproxy 启动时会直接报错,告诉你这个算法不能在 TCP 模式下使用。反过来,rdp-cookie 是为远程桌面协议场景设计的,通常在四层模式配合 mode tcp 使用。理解这条分界线,能帮你少走很多弯路。
1.3 权重和maxconn是算法的“调校参数”
算法本身只是调度策略,真正让算法贴合业务的是 weight 和 maxconn 这两个参数。weight 表示服务器权重,默认都是1,权重越大,算法会越倾向于把流量分给这台机器。maxconn 表示单台服务器的最大连接数,是硬性保护阈值。
在 roundrobin 里,权重决定分配比例;在 leastconn 里,权重是连接数的分母,也就是说连接数除以权重最小的机器会优先收到新请求;在 source、uri 这类哈希算法里,权重影响哈希映射的目标选择概率。maxconn 则像是一个安全阀,不管算法怎么选,单机连接数不能超过这个值,一旦达到上限,Haproxy 会把这台机器视为“满”,新请求会尽量分配给其他机器。
我见过很多生产事故,本质上是 weight 和 maxconn 的配置比例不协调。比如给一台 8 核机器配了 weight 8,
