根本原因是宿主机 conntrack 对空闲 established 连接超时清理(如默认600秒),导致 nginx keepalive 连接被静默中断;需协同调整 nginx 保活配置、宿主机 conntrack 超时,或改用 host/macvlan 网络绕过 nat。

这个问题本质是 Docker 默认的 bridge 网络(即 NAT 模式)下,宿主机内核的 conntrack 机制对空闲连接做了超时清理,而 Nginx 的 keepalive 连接恰好落在这个“空闲”范围内,未被上层应用感知,导致连接被静默中断。
宿主机 conntrack 超时是根本原因
Docker 使用 iptables + netfilter 实现容器网络转发,所有进出容器的连接都会被 conntrack 记录。默认情况下:
- TCP established 状态连接的超时时间通常是 432000 秒(5 天) —— 这没问题
- 但 TCP fin_wait / time_wait / close_wait 等中间状态的超时往往只有 120 秒左右
- 更关键的是:**Nginx 长连接在无流量时处于 established 状态,但某些 Linux 内核版本(尤其是较老或定制发行版)会将“无数据交互的 established 连接”也纳入短超时逻辑(如 600 秒)
- 一旦 conntrack 表项被删除,后续该五元组的包会被宿主机丢弃(表现为 RST 或无响应),Nginx 和客户端都以为连接还活着
Nginx 侧需主动探测保活
仅靠 TCP keepalive 不够,因为它的默认行为不保证穿透 NAT 设备(很多路由器/NAT 网关会忽略或截断 TCP keepalive 包)。应在应用层增强保活:
MiniMax 图片理解 + 网络搜索 MCP 工具。适配 Docker 环境(极空间等),支持图片 OCR 识别、图像内容理解、网络搜索。API Key 安全存储在本地 credentials 文件,不暴露在代码中。
- 启用
keepalive_timeout,但必须配合keepalive_requests合理设置(例如keepalive_timeout 60s;+keepalive_requests 100;) - 在 upstream 中显式开启长连接,并设置 socket 选项:
upstream backend {<br> server 172.18.0.10:8080;<br> keepalive 32;<br>}
并在 location 中使用:proxy_http_version 1.1;<br>proxy_set_header Connection '';
- 对关键接口,客户端应定期发送轻量心跳(如
HEAD /health),比依赖底层更可靠
调整宿主机 conntrack 超时(谨慎操作)
若确认是 conntrack 清理导致,可在宿主机执行(需 root 权限):
- 查看当前设置:
sysctl net.netfilter.nf_conntrack_tcp_timeout_established - 临时调大(例如设为 1 小时):
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600 - 永久生效:写入
/etc/sysctl.conf并运行sysctl -p - 注意:过大的值会耗尽 conntrack 表(默认通常 65536 条),建议结合
nf_conntrack_max一并评估
更彻底的解法:绕过 Docker NAT
如果业务对连接稳定性要求高,推荐跳过 bridge 网络:
- 使用
host网络模式:docker run --network host ...,容器直接共享宿主机网络命名空间,无 NAT、无 conntrack 干预 - 使用
macvlan或ipvlan网络,为容器分配独立 IP,走二层转发,同样规避 NAT 超时问题 - Kubernetes 场景可考虑 CNI 插件(如 Calico、Cilium)的 direct routing 模式
不复杂但容易忽略:真正起作用的不是 Nginx 的 keepalive 配置本身,而是它是否与上游服务、宿主机网络栈、甚至云厂商的负载均衡器(如 AWS ALB、阿里云 SLB)的空闲超时形成匹配链。逐层检查超时值并确保最小值主导全局行为,才能根治这类“悄无声息断连”。










