conntrack 表满后即使清空也立即复满的业务场景与 tcp_timeout_established 调优

1次阅读

conntrack表持续满的根本原因是连接生命周期过长,尤其是established状态连接滞留;需结合业务模型合理调小net.netfilter.nf_conntrack_tcp_timeout_established,并验证条目是否真实衰减,同时排查assured标记、unreplied半开连接及应用层关闭逻辑。

conntrack 表满后即使清空也立即复满的业务场景与 tcp_timeout_established 调优

conntrack 表满后清空即复满,本质是连接生命周期过长

这不是 conntrack -F 没用,而是新连接持续涌入、旧连接迟迟不释放。典型表现是:nf_conntrack_count 瞬间回到上限,dmesg 里反复出现 "nf_conntrack: table full, dropping packet"。根本原因往往不是并发量突增,而是大量连接卡在 ESTABLISHED 状态不退场。

  • 常见于长连接服务(如 websockethttp/2 后端、数据库连接池未正确关闭)
  • 也见于客户端异常断连但服务端未触发 FIN/RST,导致 conntrack 条目长期滞留
  • linux 默认 net.netfilter.nf_conntrack_tcp_timeout_established 是 432000 秒(5 天),远超业务实际需要

tcp_timeout_established 调优必须结合业务连接模型

盲目调小 net.netfilter.nf_conntrack_tcp_timeout_established 可能引发连接被误杀,尤其对长周期数据传输或心跳保活的场景。得先确认你的连接“应该”存活多久:

  • HTTP API(短连接):30–120 秒足够,设为 120 即可
  • WebSocket 或 MQTT 长连接:依赖心跳间隔,timeout 应设为心跳周期的 2–3 倍(例如心跳 30s,设为 90
  • 数据库连接池(如 pgBouncer、HikariCP):需与池的 idle timeout 对齐,通常 300(5 分钟)较安全
  • 不要低于 60:太短易受网络抖动影响,TCP 重传或延迟 ACK 可能导致连接提前被回收

调优后必须验证 conntrack 条目真实衰减行为

改完 sysctl 不代表生效——要确认内核已加载且条目开始自然释放。容易忽略的点:

  • 执行 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=120 后,用 sysctl net.netfilter.nf_conntrack_tcp_timeout_established 确认值已更新
  • conntrack -L | wc -l 看总数没用,要观察 conntrack -L | grep "ESTABLISHED" | head -20,检查每个条目的 [ASSURED] 和时间戳是否开始滚动更新
  • 如果仍不下降,检查是否有连接被标记为 [ASSURED]:这类连接不受 timeout 控制,通常由 iptables 的 CT target 或 nfqueue 主动保活,需排查规则链
  • 容器环境(如 kubernetes)要注意:节点级 sysctl 修改不自动透传到 Pod,需通过 securityContext.sysctls 显式配置

别只盯 ESTABLISHED,TIME_WAIT 和 UNREPLIED 也可能是隐形主力

conntrack -S 查看各状态计数,常发现 unrepliedtime_wait 占比异常高:

  • unreplied 高:说明有大量半开连接(SYN 到了,SYN-ACK 没回),检查防火墙拦截、后端宕机或 SYN flood 攻击
  • time_wait 高:不是 conntrack 问题,是 socket 层资源,需调 net.ipv4.tcp_fin_timeout 或启用 net.ipv4.tcp_tw_reuse(仅客户端适用)
  • 真正卡住 conntrack 表的,往往是 established + unreplied 组合——前者靠 timeout 缩短,后者得从网络连通性或应用层握手逻辑查起

调参只是止血,conntrack 持续满,终究是连接没按预期关闭。得顺着日志和 conntrack -E 实时事件,找到哪类连接不走 FIN 流程,这才是根因。

text=ZqhQzanResources