netstat 和 ss 不显示异常是因为它们只查看 socket 层连接状态,而 conntrack 表满时新连接在进入协议栈前就被 nf_conntrack 拒绝,根本未到达 socket 层。

conntrack 表满时为什么 netstat 和 ss 都不显示异常
因为 netstat 和 ss 只查 socket 层的连接状态(如 ESTABLISHED、TIME_WAIT),而 conntrack 是 netfilter 的连接跟踪表,用于 NAT、防火墙规则匹配等。新连接在进入协议栈前就被 nf_conntrack 拒绝了,根本到不了 socket 层,所以这两个工具完全看不到任何“新连接尝试”的痕迹。
快速确认 conntrack 表是否已满
直接看内核统计和当前使用量,比翻日志更快:
- 运行
cat /proc/sys/net/netfilter/nf_conntrack_count查当前条目数 - 运行
cat /proc/sys/net/netfilter/nf_conntrack_max查上限值 - 如果前者接近或等于后者(比如 >90%),基本就是瓶颈所在
- 补充验证:
dmesg -T | tail -20 | grep -i "nf_conntrack: table full",有这条日志就实锤了
常见导致 conntrack 泛滥的场景和对应检查点
不是所有连接都会进 conntrack 表,但以下几类特别容易堆积:
- 大量短连接 + 未启用
nf_conntrack_tcp_be_liberal=1:TCP FIN/RST 乱序时会卡住连接状态,建议开启 - UDP 流量(尤其是 DNS、NTP):默认超时长达 30 秒,且无握手确认,极易堆积;可通过
sysctl net.netfilter.nf_conntrack_udp_timeout_stream和_timeout分别调低 - 容器环境(Docker/Podman):每个容器网络命名空间都独立维护 conntrack 表,宿主机上看到的是总和,但实际可能某个 namespace 已满;用
nsenter -n -t $PID -- cat /proc/sys/net/netfilter/nf_conntrack_count检查具体容器 - iptables 规则中用了
-m state或-m conntrack:即使没做 NAT,只要加载了 nf_conntrack 模块并触发匹配,就会建连接记录
临时缓解与长期调优的关键参数
别只加 nf_conntrack_max,要结合业务特征调整超时和回收逻辑:
- 临时扩容(重启后失效):
sysctl -w net.netfilter.nf_conntrack_max=131072 - 缩短 TCP 非活跃连接超时:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=43200(默认 43200 秒 = 12 小时,对多数服务太长) - 加快 TIME_WAIT 回收:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30(默认 120 秒) - 启用自动垃圾回收(尤其高并发突增场景):
sysctl -w net.netfilter.nf_conntrack_gc_thresh_high=110000,同时设_low和_max形成水位区间 - 注意:修改后需运行
sysctl -p持久化,且某些参数(如nf_conntrack_max)在模块加载后不可动态增大,必须先rmmod nf_conntrack再重设再modprobe
真正麻烦的不是调参本身,而是不同协议、不同 namespace、不同内核版本对同一参数的响应差异——比如 5.10+ 内核里 nf_conntrack_tcp_be_liberal 默认已开,但 4.19 可能还关着,得挨个核对。








