Linux 出现 nf_conntrack: table full 怎么办?连接跟踪表排查、扩容与超时优化
本内容发表于:2026-08-27 16:23:51
浏览量
1048

Docker、Kubernetes 节点连接偶发超时?排查 conntrack 表耗尽

容器服务出现间歇性超时时,应用日志可能只有 connection timed out、DNS 查询失败或访问上游偶发中断。Pod 重启后故障短暂消失,但节点过一段时间又复现。如果节点内核同时记录下面的日志,应把排查范围移到宿主机连接跟踪表:

nf_conntrack: table full, dropping packet

Docker 网桥、Kubernetes Service、节点 SNAT 和出口网关都可能依赖 Netfilter 连接跟踪。表满之后,新流量在到达应用之前就可能被丢弃,因此只检查容器端口和进程状态往往找不到原因。

一、必须在节点上检查,而不是只进容器

先登录出现故障的宿主机或 Kubernetes 节点:

dmesg -T | grep -i 'nf_conntrack.*table full'
journalctl -k --since '-1 hour' | grep -i conntrack
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max

计算使用率:

count=$(sysctl -n net.netfilter.nf_conntrack_count)
max=$(sysctl -n net.netfilter.nf_conntrack_max)
awk -v c="$count" -v m="$max" \
  'BEGIN {printf "usage=%.1f%% (%d/%d)\n", c*100/m, c, m}'

nf_conntrack_count 表示当前分配的流条目数,nf_conntrack_max 表示允许的最大条目数。两者由宿主机内核维护,普通容器看到或修改这些参数的能力取决于网络命名空间和权限。(docs.kernel.org)

Kubernetes 环境先找出异常 Pod 所在节点:

kubectl get pod -A -o wide
kubectl get node -o wide

如果只有部分节点报错,不要立即把问题归因于整个集群网络。优先比较异常节点与正常节点的条目上限、当前使用率、Pod 数量和出口流量。

二、区分套接字耗尽和 conntrack 耗尽

查看本机套接字摘要:

ss -s
ss -ant | awk 'NR>1 {print $1}' | sort | uniq -c | sort -nr

再查看连接跟踪数量:

conntrack -C
conntrack -S

conntrack 工具可以显示条目计数、内核统计和经过筛选的连接记录。(netfilter.org)

两组数字不相等并不异常。ss 主要观察节点上的套接字,而 conntrack 还会记录经过节点转发、NAT 或状态防火墙处理的连接。例如,承担 Pod 出口 SNAT 的节点可能有大量连接跟踪记录,却没有同等数量的本地应用连接。

三、找出条目主要来自哪些容器或 Pod

先对来源地址做采样统计:

conntrack -L -o extended 2>/dev/null |
awk '{
  for (i=1; i<=NF; i++) {
    if ($i ~ /^src=/) {
      split($i, a, "="); print a[2]; break
    }
  }
}' |
sort | uniq -c | sort -nr | head -n 30

连接表很大时,完整转储可能给繁忙节点增加负担。先执行 conntrack -C 和 conntrack -S,确认有必要后再在单台节点上短时间采样。

Docker:把来源 IP 映射回容器

docker ps -q | xargs -r docker inspect \
  --format '{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}'

将统计结果中的来源 IP 与容器 IP 对照。某个容器条目明显偏多时,继续检查它是否频繁请求不可达地址、关闭了连接池、不断重试,或在短时间创建大量 DNS 和 HTTP 请求。

Kubernetes:把来源 IP 映射回 Pod

kubectl get pod -A -o wide --sort-by=.status.podIP

如果使用了覆盖网络、隧道或特定 CNI,节点上看到的地址可能经过转换。应结合当前 CNI 的数据路径确认原始来源,不能假设所有 conntrack 地址都能直接对应 Pod IP。

四、重点排查四类容器流量

1. 没有复用的 HTTP 请求

应用每次请求都新建 TCP 连接,会快速增加连接创建和销毁频率。检查客户端是否启用了 Keep-Alive、连接池以及合理的空闲连接数量。

ss -ant state established | wc -l
ss -ant state time-wait | wc -l

如果修复连接池后,业务请求量不变但 conntrack 增长速度明显下降,说明优化方向有效。

2. 失败后无退避重试

上游故障时,多个副本同时快速重试,会持续创建新连接。重试应设置次数上限、指数退避和随机抖动,避免所有 Pod 在同一时间发起下一轮请求。

检查应用日志中的单位时间重试次数,并与下面的连接跟踪趋势对照:

while sleep 5; do
  printf '%s ' "$(date '+%T')"
  sysctl -n net.netfilter.nf_conntrack_count
done

3. 高频 DNS 或短 UDP 事务

查看协议分布:

conntrack -L 2>/dev/null |
awk '{print $1}' |
sort | uniq -c | sort -nr

检查 UDP 超时:

sysctl net.netfilter.nf_conntrack_udp_timeout
sysctl net.netfilter.nf_conntrack_udp_timeout_stream

内核为普通 UDP 和 UDP 流分别提供超时参数。(docs.kernel.org)

如果确认节点只承载短事务,并完成了测试,可以小幅降低参数:

sysctl -w net.netfilter.nf_conntrack_udp_timeout=20
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=60

不要在不了解实时音视频、隧道或其他长 UDP 会话的情况下直接应用这些值。

4. 出口集中在少数节点

如果大量 Pod 通过少数节点进行 SNAT,即使各应用流量正常,节点也可能承担过多连接状态。检查节点间 Pod 数、出口流量和 conntrack 使用率是否明显不均衡。

可选处理方式包括:

  • 调整 Pod 调度,分散高出口流量工作负载;
  • 扩展出口节点或 NAT 网关容量;
  • 减少多层重复 NAT;
  • 为高并发客户端启用连接复用;
  • 根据实际流量提高节点 conntrack 上限。

五、应急扩容节点连接跟踪表

节点还有足够内存时,可临时提高上限:

sysctl -w net.netfilter.nf_conntrack_max=262144

持续观察:

watch -n 2 'sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max'
journalctl -kf | grep --line-buffered -i conntrack

如果使用率快速再次达到新上限,应优先限制异常来源或减少无效重试,不要继续机械翻倍。

在普通 Linux 节点上,可持久化为:

cat >/etc/sysctl.d/90-conntrack.conf <<'EOF'
net.netfilter.nf_conntrack_max = 262144
EOF
sysctl --system

受管 Kubernetes 的节点镜像可能在重建后覆盖本地文件。此时应通过节点模板、启动脚本、受支持的节点配置接口或镜像构建流程保存参数,并在节点替换后重新验证。

六、不要把清空连接表当成节点修复

conntrack 支持删除和清空记录,但这些操作会影响正在使用的连接。(netfilter.org)

# 高风险:不要在承载流量的节点上直接执行
conntrack -F

清空后数字会立即下降,但 NAT 映射和状态防火墙记录也会丢失。更稳妥的流程是先将节点摘出负载、等待连接排空,再根据明确条件删除异常记录或重启网络组件。

也不要为了降低条目数而全局关闭 conntrack。Docker 端口映射、Kubernetes Service、SNAT 和状态防火墙可能依赖它;改变跟踪规则前必须理解当前数据路径。

七、完成修复后的验证

节点侧

sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
journalctl -k --since '-15 min' | grep -i conntrack
slabtop -o | grep -E 'nf_conntrack|nf_conntrack_expect'

确认条目数在峰值结束后回落,内核不再记录表满丢包,同时内存消耗处于可接受范围。

Docker 侧

docker ps
docker stats --no-stream

检查异常容器是否仍在高频创建连接,连接池和重试配置是否已经随新版本生效。

Kubernetes 侧

kubectl get pod -A -o wide
kubectl get events -A --sort-by=.lastTimestamp | tail -n 50

从集群内连续请求 DNS、ClusterIP 服务和外部依赖,并从集群外执行健康检查。只验证 Pod 状态为 Running 不够,Pod 可以正常运行但节点仍在网络层丢弃新连接。

八、建议建立的监控

至少记录每个节点的:

  • nf_conntrack_count;
  • nf_conntrack_max;
  • 使用率及增长速度;
  • 内核 conntrack 丢包或插入失败;
  • 节点内存;
  • Pod 数量和出口流量;
  • DNS、服务间调用及外部请求成功率。

告警应带上节点名并与业务探测关联。这样可以区分单节点容量不足、异常 Pod 制造连接风暴和集群整体出口设计不足。

总结

容器网络中的 nf_conntrack: table full 是节点级故障,不是简单的 Pod 端口问题。先在宿主机确认条目使用率,再把来源地址映射回容器或 Pod,检查连接池、重试、UDP 事务和出口分布。临时扩容可以恢复新连接,但长期修复要减少无效连接、分散 NAT 压力,并确保节点重建后参数和监控仍然存在。