连接排空(Connection Draining,也称连接耗尽、优雅下线)是负载均衡器在把某一台后端服务器移出服务池时,不再向它分发新的连接,同时允许已经建立的连接在限定的时间内自然完成后再关闭连接的机制。它的目标是避免用户在服务升级、故障替换或缩容时遭遇请求被硬生生掐断,从而保证业务连续性和用户体验。
连接排空要解决的问题
负载均衡(Load Balancing)通过反向代理把请求分散到多台后端服务器,常见的实现包括 Nginx、HAProxy、AWS 应用负载均衡器(ALB)等。正常情况下,请求到达均衡器后会被转发到某台”健康”的后端节点处理。当某台节点需要下线,例如进行内核升级、代码发布或硬件维护时,如果直接把它从服务池中移除,正在处理中的在途请求(in-flight request)会立刻被打断,客户端收到的可能是连接重置、超时或响应残缺。
在途请求与一次性 HTTP 请求不同。一次普通的 GET 请求往往在几百毫秒内完成,断开的伤害有限;但下面的场景对连接中断极为敏感:
- 长连接(Keep-Alive):客户端与服务器保持的连接可能持续数分钟。
- 实时推送:基于 WebSocket 或服务器发送事件(SSE)的双向连接会长时间存活。
- 长轮询(Long Polling):客户端发起请求后服务器一直挂起,直到有新数据或超时才返回。
- 大数据量导出:文件下载、视频转码等任务可能持续数十秒甚至更久。
一旦这些连接被强制中断,用户必须手动重试,部分状态(比如分片上传的进度、会话登录态)可能丢失,最终表现为页面报错或任务失败。
连接排空的工作原理
连接排空的工作过程通常分成三个阶段,核心是把”新增流量”和”存量流量”分开处理。
第一阶段:停止分发新连接
均衡器先通知调度器,把目标节点的状态从”活跃”(active)改为”排空中”(draining)。从这一刻起,新的请求不再路由到该节点,而是由其余正常节点分担。这一步保证了不再产生新的在途连接。
第二阶段:等待存量连接自然结束
已经建立的连接仍然可以继续收发数据,直到它们自然完成。系统为这个阶段设置一个上限,即排空超时(drain timeout / deregistration delay)。只要连接在超时时间内结束,就实现了真正的”优雅下线”(graceful shutdown)。
第三阶段:超时后强制断开
如果某条长连接在超时时间到达后仍然存活,均衡器会强制将其关闭,并把该节点彻底从服务池中移除。超时时间因此是一个权衡:设置过短,长连接任务会被掐断;设置过长,维护窗口会被拖得很久,下线动作迟迟无法完成。

主流负载均衡器的连接排空实现
不同产品对连接排空有各自的术语和配置方式,下表整理了常见平台的对应关系。
| 平台 | 术语 | 默认超时 | 适用连接 |
|---|---|---|---|
| AWS 应用负载均衡器 (ALB) | Deregistration Delay | 300 秒 | HTTP/HTTPS、WebSocket |
| AWS 网络负载均衡器 (NLB) | Connection Termination | 无内置排空,依赖目标组超时 | TCP/UDP、TLS |
| Nginx | down + 慢启动 / 手动关闭 | 需自行设计 | HTTP 长连接、WebSocket |
| HAProxy | DRAIN 状态 | 依赖连接自然结束 | TCP/HTTP |
| Kubernetes Service | terminationGracePeriodSeconds | 30 秒 | Pod 内连接 |
| Envoy | drain_timeout | 600 秒 | HTTP/HTTP2/gRPC |
在 AWS 上配置连接排空
AWS 把连接排空称为”Deregistration Delay”,通过目标组属性控制。下面的命令把延迟设为 300 秒:
# 修改目标组属性,设置取消注册延迟为 300 秒 aws elbv2 modify-target-group-attributes \ --target-group-arn arn:aws:elasticloadbalancing:region:account:targetgroup/my-tg/xxxx \ --attributes Key=deregistration_delay.timeout_seconds,Value=300
设置后,当目标组中的某台实例被标记为取消注册时,ALB 会停止向它发送新请求,并等待最多 300 秒让在途连接自然结束。
在 HAProxy 中启用排空
HAProxy 通过把服务器切到 DRAIN 状态实现类似效果,该状态下的服务器不接收新连接,但存量连接继续保留:
# 将后端 backend1 节点切入 DRAIN 状态,停止新连接 echo "set server web/backend1 state DRAIN" | socat stdio /var/run/haproxy.sock # 确认当前状态 echo "show servers state" | socat stdio /var/run/haproxy.sock
在 Kubernetes 中实现优雅下线
Kubernetes 依赖 Pod 的优雅终止机制,通过 terminationGracePeriodSeconds 控制宽限期,同时要求业务进程监听 SIGTERM 信号并在宽限期内完成收尾:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
template:
spec:
terminationGracePeriodSeconds: 60
containers:
- name: app
image: nginx:1.25
在 Kubernetes 中,Pod 被删除时先被移出 Endpoint 列表,随后收到 SIGTERM,应用应在宽限期内停止接收新连接并完成存量请求,超时后由 kubelet 发送 SIGKILL。
关键参数如何选择
排空超时是配置的核心。下表列出常见取值与适用场景,供排障时参考。
| 超时值 | 适用场景 | 风险 |
|---|---|---|
| 0-30 秒 | 无状态短请求 API、一次性页面 | 长连接任务易被中断 |
| 60-300 秒 | 常规 Web 应用、文件上传下载 | 维护窗口适中,风险可控 |
| 300-900 秒 | 视频转码、批量导出、长轮询 | 节点下线慢,占用资源久 |
| 大于 900 秒 | WebSocket 实时会话且无法重连 | 强烈不建议,运维受阻 |
选择超时时间时,应先统计线上请求的 P95 完成时长,把排空超时设置为其 1.5 到 2 倍,再结合是否支持客户端自动重连做调整。

常见的连接排空排查
即使配置了连接排空,生产环境仍可能出现请求中断。下表整理了几类高频问题及其排查方向。
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 新请求仍进入正在下线的节点 | 排空未生效或健康检查判定延迟 | 查看均衡器日志与节点状态;确认状态已切为 draining |
| 存量连接在超时前被强制断开 | 排空超时设置过短 | 统计请求 P95 时长,调大超时 |
| 下线动作迟迟无法完成 | 存在永不结束的长连接 | 检查 WebSocket 心跳,必要时由应用侧主动关闭 |
| 节点排空后业务仍有报错 | 客户端未实现重连,会话状态未同步 | 在前端加入自动重试,确认会话保持已剥离该节点 |
| 排空后资源未释放 | 超时过长或进程未退出 | 配合进程优雅退出与最大宽限期检查 |
常见误区与边界条件
连接排空不是万能的,使用前需要厘清几个边界。第一,它只解决”已有连接”的善后问题,无法阻止新请求因调度延迟而偶发进入,因此通常需要配合健康检查(Health Check)把节点标记为不健康。第二,对无状态且支持快速重连的服务,可以适当缩短超时,不必为了追求零中断而拉长维护窗口。第三,连接排空与会话保持(Session Persistence)不同,前者处理节点下线,后者决定请求固定到哪台节点,二者需要分别配置。第四,排空只对均衡器可控的连接生效,若客户端直连后端(绕过均衡器),排空机制完全失效,这类架构应在设计阶段避免。关于单台节点与集群在容量规划上的差异,可参考 独立服务器与VPS的区别 一文。
参考资料
- 独立服务器与 VPS 的选型与运维可参考 独立服务器与VPS 分类。
- 连接排空通常运行在 Linux 环境,操作系统-Linux 分类覆盖相关系统知识。
- 云上与自有节点混布时,云计算与AI 分类可帮助理解云均衡器行为。
- 关于海外服务器部署均衡架构,可阅读 美国CN2服务器租用对SEO优化的影响 一文。
连接排空的价值在于把”节点下线”从一次有损的强制中断,变成一次可控、可预期的平滑切换。理解它的原理、超时参数与排查思路,是搭建高可用负载均衡体系的基本功。

微信扫一扫打赏
支付宝扫一扫打赏