负载均衡作为业务流量的入口,其稳定性直接决定了整个服务的可用性。而健康检查和会话保持,正是SLB配置中最容易被忽视、又最容易引发线上故障的两个环节。健康检查参数设置得激进,后端稍有抖动就被摘除流量;设置得保守,服务器真挂了却迟迟切不走流量。会话保持配错场景,轻则用户频繁掉线重登录,重则单机压力过大被打挂。这篇文章就把这两个配置项彻底讲透。

健康检查的底层机制:SLB是怎么判断后端是否存活的
要调优健康检查,首先得明白SLB的探测逻辑。以阿里云CLB为例,健康检查由LVS集群或七层集群发起,按照配置的监听规则,周期性地向后端服务器发送探测请求。四层监听走TCP三次握手探测,即尝试与后端的业务端口建立连接,连接成功即认为健康;七层监听则发送HTTP HEAD或GET请求,根据返回的状态码判断健康状态。
这里有一个很多人没意识到的细节:四层TCP探测只验证端口是否能建立连接,并不代表应用真的能处理请求。比如一个Java应用发生了死锁,Tomcat进程还在监听8080端口,TCP探测照样通过,但业务请求已经全部超时。所以对于关键业务,强烈建议使用七层HTTP探测,并让健康检查接口真正执行一段轻量级的业务逻辑,例如访问一次数据库连接池或检查缓存可用性。
另一个关键是状态机转换逻辑。假设健康阈值设置为3,不健康阈值设置为2,那么一台正常的服务器如果连续2次探测失败,会被标记为不健康并停止转发流量;而一台不健康的服务器需要连续3次探测成功,才会重新恢复接收流量。注意这里要求的是连续成功或连续失败,中间只要有一次结果相反,计数器就会重置。理解了这一点,后面调参就有了依据。
四个核心参数如何权衡:速度与误判的博弈
健康检查的核心参数有四个:探测间隔、响应超时、健康阈值、不健康阈值。它们共同决定了两个关键指标——故障发现时间(后端挂掉到被摘除的时间)和恢复时间(后端恢复到重新接流的时间)。故障发现时间的理论上限是:响应超时 × 不健康阈值 + 探测间隔 × (不健康阈值 - 1)。
以默认配置为例,间隔10秒、超时5秒、不健康阈值3次,最坏情况下需要5×3 + 10×2 = 35秒才能摘除一台故障服务器。对于高并发的核心业务,35秒的故障窗口可能导致大量请求失败,这时可以适当调小间隔和阈值,比如间隔5秒、阈值2次,最坏10秒左右完成摘除。但也不能一味求快:如果后端存在GC停顿、慢SQL等情况,探测响应偶尔超过1秒,过短的超时时间会造成频繁误摘除,产生流量震荡。被摘除的服务器恢复后流量突然涌入,压力升高导致探测再次超时,又被摘除,如此往复。
实际生产中比较稳妥的经验值是:普通Web服务用HTTP探测,间隔5到10秒,超时5秒,健康阈值3次,不健康阈值3次;对延迟极不敏感的内网服务可以用TCP探测加更长的间隔。如果你的应用有明显的Full GC,建议先优化JVM,或者把超时时间放宽到略高于GC最大停顿时间,同时把不健康阈值提高到4次以上,避免单次长停顿就触发摘除。
会话保持的三种方式与适用场景
会话保持的目的是让同一个客户端的请求尽量落到同一台后端服务器上,常见于登录态存在本地内存、或者WebSocket长连接的场景。实现方式主要有三种:源IP粘性、Cookie植入和自定义Cookie。
源IP粘性是四层监听的方案,SLB根据请求的源IP地址做哈希,把相同来源的请求转发到固定后端。它配置简单、对应用透明,但缺点也很明显:客户端IP经过多层代理后会高度集中(比如整个公司出口只有一个IP),导致流量倾斜;客户端IP变化(移动网络切换、运营商动态IP)也会导致会话中断。此外阿里云四层监听开启会话保持后,默认保持时间为900秒,空闲超过这个时间会被重新调度。
Cookie植入是七层监听推荐的方案,SLB在客户端首次请求的响应中插入一个Cookie(例如阿里云的SLB后插入模式),后续请求带上这个Cookie,SLB就识别出应该转发到哪台后端。应用完全无需改造,是大多数场景的首选。而自定义Cookie模式则是由后端应用自己Set-Cookie,SLB根据指定的Cookie名做粘性,适合已经有一致性哈希逻辑、或者需要在服务端控制会话时长的业务。注意使用自定义Cookie时,所有后端节点必须使用相同的Cookie名称,否则SLB无法正确识别。
Nginx与阿里云SLB的配置实践
如果是自建Nginx做负载均衡,健康检查和会话保持的开源实现可以参考下面的配置。Nginx开源版自带的被动健康检查通过max_fails和fail_timeout实现,配合ip_hash或sticky实现会话保持:
upstream backend {
# 源IP哈希实现会话保持(简单但有流量倾斜风险)
ip_hash;
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.12:8080 backup;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_connect_timeout 3s; # 连接超时
proxy_read_timeout 10s; # 读取超时,需覆盖后端最慢接口
proxy_next_upstream error timeout http_502 http_503;
}
}max_fails=3 fail_timeout=30s的含义是:30秒内失败3次则标记为不可用30秒。这里要注意,Nginx被动检查只能感知正在处理的请求失败,感知速度取决于流量大小,低峰期一台故障服务器可能长时间没被摘除。如果需要主动探测,建议使用第三方模块nginx_upstream_check_module,或者直接在前面挂一层阿里云SLB负责健康检查。
在阿里云SLB上配置时,还有几个容易踩的坑值得提醒。第一,七层监听的HTTP健康检查默认路径是根路径/,如果后端对这个路径做了鉴权拦截,返回302或401会被判定为不健康,正确做法是单独提供一个不需要鉴权的/healthz接口,并把正常状态码配置为http_2xx。第二,开启会话保持后,如果后端某台服务器故障被摘除,它上面的会话会整体漂移到其他节点,登录态存本地的应用会导致这些用户集体掉线,所以关键业务尽量把Session放到Redis集中存储,会话保持只作为辅助手段。第三,权重与健康检查是联动的,摘除后恢复的服务器流量是瞬间恢复的,大流量场景建议配合连接平滑 draining 或者逐步调高权重的方式灰度恢复。
总结一下调优思路:健康检查追求的是在快速发现故障和避免误判之间找平衡,参数要结合应用的响应特性(GC停顿、冷启动时间)来定;会话保持优先选Cookie植入,能不用粘性就不用,把无状态化作为架构的长期目标。把这两块配置理解透,你的SLB才能真正扛住线上各种异常场景。