conntrack表满导致新SYN包被丢弃,而ss -s仅显示socket层连接状态,故二者数值不一致;需通过conntrack -S的insert_failed、/proc/net/nf_conntrack条目数及日志“table full”确认溢出。

conntrack 表满但 ss -s 显示连接数正常?这是两个维度的问题
没错,ss -s 统计的是当前 socket 层的连接状态(ESTAB、TIME-WAIT 等),而 conntrack 表满影响的是 netfilter 的连接跟踪状态——新 TCP 三次握手 SYN 包进不来,根本到不了 socket 层。所以你会看到 ss -s 里 ESTAB 数量稳定甚至下降,但客户端连不上、超时重传、SYN timeout 错误频发。
确认 conntrack 表是否真的溢出
别只看 sysctl net.netfilter.nf_conntrack_count,它只是当前 tracked 连接数,不等于是否丢包。关键要看内核是否开始 drop:
- 执行
cat /proc/net/nf_conntrack | wc -l和sysctl net.netfilter.nf_conntrack_max对比,接近或等于即为满 - 检查丢包:
grep "nf_conntrack: table full" /var/log/messages或dmesg -T | grep "table full" - 更直接:
conntrack -S输出中关注insert_failed计数器,非零说明已开始丢新连接
为什么 conntrack -L 看不到大量连接,但表却满了?
常见于短连接 + 高频新建场景,比如 HTTP 轮询、健康检查、DNS 查询。这些连接很快关闭,但 conntrack 条目不会立刻释放——默认要等 net.netfilter.nf_conntrack_tcp_timeout_time_wait(通常 120s)甚至更久。你用 conntrack -L 抓快照时可能刚巧没捕获到峰值,但瞬时插入失败已经发生。
- 用
watch -n 1 'conntrack -S'观察entries和insert_failed实时变化 -
conntrack -L | awk '{print $4}' | sort | uniq -c | sort -nr | head查看哪些源 IP/端口占最多条目(常暴露扫描或 misbehaving client) - 注意:启用
net.netfilter.nf_conntrack_tcp_be_liberal=1可缓解乱序/重传导致的假连接残留,但不解决根本容量问题
调优与规避的关键参数和限制
单纯加大 nf_conntrack_max 不是万能解,它吃内存(每个条目约 376 字节),且在高并发下锁竞争明显。优先做减法:
- 对明确不需要跟踪的流量 bypass conntrack:
iptables -t raw -A PREROUTING -p tcp --dport 8080 -j NOTRACK(适用于直通代理、L4 LB 后端) - 缩短超时时间:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30(需同步确认应用无 TIME-WAIT 相关异常) - 避免在容器环境重复跟踪:Docker 默认启用 conntrack;Kubernetes 中若用 kube-proxy iptables 模式,又叠加 host 上的 conntrack,容易 double-track
- 注意:修改
nf_conntrack_max后,nf_conntrack_buckets(哈希桶数)建议设为 max 的 1/4 ~ 1/2,否则哈希冲突加剧性能下降
真正难处理的是“连接未完成就堆积”的情况——比如 SYN flood、后端响应慢导致连接卡在 SYN_RECV 状态过久,这种 conntrack 条目会一直占着直到超时,比正常 ESTAB 更耗资源,也最难从日志里直接定位。










