HAProxy 健康检查与慢启动配置实战

HAProxy 健康检查与慢启动配置实战封面

负载均衡器最常见的翻车场景,不是性能不够,而是后端节点重启的那几十秒:流量仍被轮流分发到正在启动的应用进程上,用户看到的是一片 502。本文化身一份实操指南,教你如何用 HAProxy 的健康检查(health check)把故障节点及时摘除,再配合慢启动(slow start)让刚上线的节点逐步承接流量,避免冷启动进程被瞬间打满。我们会围绕一套可直接复制的服务器配置展开,覆盖参数含义、完整配置和上线后的验证方法,适合在 VPS虚拟专用服务器)或独立服务器上自建负载均衡的运维同学照做。

为什么默认的健康检查不够用

HAProxy 对每个 server 默认只做 TCP 层检查:只要端口 accept 了连接,节点就算健康。问题在于,应用进程”端口已监听”和”能正常处理请求”之间往往有数秒到数十秒的差距——Java 服务还在加载 Spring 上下文、PHP-FPM 进程池还没预热 OPcache、数据库连接池尚未建立。此时 HAProxy 仍在往里塞请求,结果就是网关超时或 502。

另一个极端同样危险:后端做代码发布重启时,两三秒的网络抖动就可能让节点被判”死亡”。如果摘除阈值设得太敏感,多台后端接连被摘,剩余节点流量瞬间翻倍,形成雪崩。所以我们需要的组合是:更真实的 HTTP 层检查(确认业务真的活着)、合理的 rise/fall 阈值(容忍瞬时抖动)、再加上慢启动(让回归节点从小流量开始逐步加压)。

这套组合对外贸站这类”白天欧美流量高峰、夜里集中发布”的业务尤其有价值:发布窗口恰好踩在流量爬升期,没有慢启动的负载均衡很容易在每天早上固定”抖一次”。如果你还想从更上游的角度审视整条链路的响应速度,可以结合我们之前整理的 TTFB 主机优化思路一起看。

健康检查参数详解:从 check 到 httpchk

先看最小配置。假设两台应用服务器 10.0.0.1110.0.0.12,跑的是 HTTP 服务:

backend web_backend
    balance roundrobin
    server app1 10.0.0.11:8080 check
    server app2 10.0.0.12:8080 check

只写 check 就是前面说的 TCP 层默认检查。要升级为 HTTP 层,加上 option httpchk 并指定探测路径:

backend web_backend
    balance roundrobin
    option httpchk GET /healthz
    http-check expect status 200
    server app1 10.0.0.11:8080 check
    server app2 10.0.0.12:8080 check

/healthz 应当是一个轻量的应用内端点:不查外部 API、不写数据库,只返回进程自身状态。http-check expect status 200 明确只有返回 200 才算健康,避免某些框架出错时仍返回 302 跳转被误判为存活。

关键的是 risefall 两个阈值,它们决定了节点状态切换的迟钝程度:

    server app1 10.0.0.11:8080 check inter 2s fall 3 rise 2

inter 2s 表示每 2 秒探测一次;fall 3 表示连续失败 3 次(即约 6 秒持续异常)才摘除节点;rise 2 表示连续成功 2 次才重新纳入。这套默认值在生产上比较稳妥:6 秒内能摘掉真故障,又不会被一次网络抖动误杀。对于会话保持类业务,还可以在 server 行加 observe layer7,让 HAProxy 顺带观察真实请求的响应,出现 5xx 时加速标记——不过它只能配合 option httpchk 一起使用,且要留意别和重试策略打架。

健康检查探测流程示意

还有一个容易被忽略的细节:健康检查的探测间隔要和后端容量匹配。如果你有 50 个后端、inter 设成 500ms,HAProxy 每秒就要发出 100 个探测请求,/healthz 本身也可能被压垮。经验值是后端超过 20 台时,把 inter 放宽到 5s,或按业务拆成多个 backend 分别探测。

慢启动:让重启节点逐步接管流量

健康检查解决”什么时候该把节点放回来”,慢启动解决”放回来之后流量加得多快”。默认情况下,节点通过 rise 检查的瞬间就会拿到全额权重,对刚重启的应用来说这是一盆冷水:JIT 还没编译热点代码、缓存还是空的、连接池正在排队建立,突然而至的全量请求会让响应时间瞬间飙高。

slowstart 参数(单位毫秒)让节点权重从 0 线性爬升到配置值:

backend web_backend
    balance roundrobin
    option httpchk GET /healthz
    http-check expect status 200
    default-server check inter 2s fall 3 rise 2 slowstart 30s
    server app1 10.0.0.11:8080 weight 100
    server app2 10.0.0.12:8080 weight 100

这里用 default-server 把公共参数收拢,新增的两台 server 只要写地址和权重。slowstart 30s 的效果是:节点通过健康检查后,前 30 秒内权重按时间线性增长——第 5 秒约为满权重的六分之一,第 15 秒一半,30 秒后全额。配合 weight 100 的基准,你可以精确控制预热节奏。

慢启动权重爬升对比示意

预热时长怎么定?一个实用的估算方法:取该服务冷启动后 P95 响应时间恢复到基线所需的时间,再乘以 2。例如发布后应用需要约 15 秒让缓存命中率回到正常水位,slowstart 30s 就是个合适的起点。对于冷启动要一分钟的 JVM 应用,直接给 slowstart 60s 甚至 120s 也不过分——慢启动的代价只是流量在剩余节点上多分担一会儿,远比把用户请求当预热牺牲品划算。

需要留意两个行为细节:其一,慢启动只在节点从 DOWN 转 UP 或 HAProxy 自身启动时生效,运行中用 set server ... weight 动态调权不会触发;其二,如果整个 backend 里的节点都处于 DOWN,那么唯一恢复的节点会跳过慢启动直接承接全部流量(总不能让服务整体不可用),这是有意设计的保护行为。

上线验证:确认配置真的生效

改完配置先做语法检查,这一步能拦住绝大部分低级错误:

haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl reload haproxy

reload 而非 restart,HAProxy 会优雅切换新旧进程,长连接不会被掐断。加载完成后,观察节点状态最直接的方式是启用统计页——在配置中加入 listen stats 段,绑一个内网端口,页面里每个节点的 UP/DOWN 状态、最近一次检查结果、当前权重一目了然。

验证慢启动有个简单的手动实验:把其中一台后端 systemctl stop 掉,等统计页显示 DOWN 后再 start。恢复的瞬间刷新统计页,你会看到该节点的”权重”列从接近 0 的数值逐秒爬升,直到 30 秒后到达 weight 100。与此同时用 watch curl 持续打 HAProxy 的入口地址,观察响应是否始终 200——如果重启期间依然全绿,说明摘除与预热都在按预期工作。

验证后验证流程示意

再补一个真实发布场景的检查清单,你可以照着核对:发布前确认统计页可访问;摘掉一台节点发布,等待其通过 rise 检查并完成 slowstart 爬升;再对第二台重复同样流程。全程统计页的会话曲线不应出现断崖。如果你的后端跑的是 WordPress 站群,还要额外确认 /healthz 端点没有走缓存层——被页面缓存接管的探测会永远返回 200,等于检查失效。WordPress 场景的前置优化可以参考这篇 WordPress 主机与性能指南

总结

健康检查和慢启动是 HAProxy 里投入产出比最高的两项配置:前者保证坏节点被及时隔离,后者保证好节点回归时不被压垮。核心参数归结起来就一组:option httpchk GET /healthzhttp-check expect status 200inter 2s fall 3 rise 2slowstart 30s 起步再按冷启动时长调整。建议你先在测试环境把上文的手动验证流程跑一遍,确认统计页的权重爬升曲线符合预期,再应用到生产。如果你正在规划整套负载均衡架构,也可以考虑从 Hostease 的服务器方案入手搭建后端集群,把更多精力留给业务本身。

本文首次发布于 2026 年 9 月 4 日。

发表评论