ss -ant 显示 established 是 tcp socket 状态,而 conntrack 表满仅影响需跟踪的连接;本地回环、未启用模块或 liberal 模式下连接可能根本不进 conntrack 表。
conntrack 表满时为什么 ss -ant 还能看到大量 ESTABLISHED?
因为 ss -ant 显示的是 socket 状态,而 conntrack 跟踪的是网络连接的四元组(源IP/端口、目标IP/端口、协议、方向)状态机。ESTABLISHED socket 只说明本地 TCP 状态是 ESTABLISHED,不意味着该连接一定在 conntrack 表里——它可能压根没被跟踪,或已被提前删除。
常见触发场景:
- 内核未启用连接跟踪(
nf_conntrack_enable=0或模块未加载),但用户误以为开启着 - 连接是本地 loopback(127.0.0.1)且启用了
net.netfilter.nf_conntrack_tcp_be_liberal=1,部分连接跳过跟踪 - 连接建立后很快关闭,但 conntrack 条目因 timeout 未及时回收,新连接又不断涌入,表满后新 SYN 报文被丢弃,老 ESTABLISHED socket 却还活着
如何确认 conntrack 表是否真满、以及哪些连接卡在表里?
直接查当前使用量和上限:
cat /proc/sys/net/netfilter/nf_conntrack_count cat /proc/sys/net/netfilter/nf_conntrack_max
若前者接近后者(比如 >95%),基本可判定表满。进一步看堆积类型:
-
conntrack -L | head -20:观察是否有大量TIME_WAIT或SYN_SENT条目(说明连接无法正常完成或释放) -
conntrack -S:查看各状态计数,重点关注insert_failed是否持续增长(每增 1 表示一个新连接因表满被丢弃) -
conntrack -L -d <code>YOUR_APP_IP:过滤特定服务 IP,确认是否集中在某几个后端连接上
为什么新连接失败却看不到 SYN 被 drop?
conntrack 表满时,内核在 nf_conntrack_invert_tuple() 或 resolve_normal_ct() 阶段直接返回 -ENOMEM,后续 netfilter hook(如 iptables INPUT)甚至收不到该包——它在连接跟踪模块就终止了,不会进入 conntrack 日志、iptables LOG target,也不会触发 tcpdump 在 raw socket 层捕获(除非用 tcpdump -i any 并确保抓到 ingress 路径最前端)。