适用场景
本文适用于 Linux 主机、NAT 网关、Docker 宿主机、Kubernetes Node 或开启防火墙规则的服务器。当业务出现偶发连接超时、DNS 查询失败、服务间调用间歇性失败,而 CPU、内存、磁盘都看起来正常时,可以把 conntrack 连接跟踪表作为重点排查对象。
典型环境包括:
- 单机部署了 Nginx、Docker、iptables、firewalld 或 kube-proxy。
- 节点承担 SNAT、DNAT、NodePort、Ingress 出入口流量。
- 短连接很多,例如爬虫、网关、日志上报、健康检查、HTTP 回调。
- 高峰期才出现异常,低峰期自动恢复。
现象描述
一次线上问题中,业务接口在高峰期偶发超时,表现为:
- 应用日志出现
connect timeout、read timeout、connection reset by peer。 - 部分容器访问外部 API 失败,但重试后成功。
- DNS 查询偶发失败,报
Temporary failure in name resolution。 - Nginx upstream 偶发 502 或 504。
- 主机 CPU、内存、磁盘 I/O 没有明显瓶颈。
查看内核日志时发现类似信息:
dmesg -T | grep -i conntrack
可能输出:
nf_conntrack: table full, dropping packet
这说明内核连接跟踪表已经达到上限,新连接无法被记录,相关数据包可能被丢弃。
conntrack 是什么
conntrack 是 Linux netfilter 框架中的连接跟踪机制。iptables、nftables、NAT、Docker 端口映射、Kubernetes Service 转发等功能,经常依赖它记录连接状态。
它会跟踪类似下面的信息:
- 源 IP、源端口、目标 IP、目标端口、协议。
- TCP 状态,例如
SYN_SENT、ESTABLISHED、TIME_WAIT。 - UDP、ICMP 等非 TCP 流量的超时时间。
- NAT 前后的地址和端口映射。
当连接跟踪表满了,新的连接状态无法插入,依赖连接跟踪的转发、NAT、防火墙规则就可能出现异常。
可能原因
conntrack 表满通常不是单点原因,而是流量模型和系统参数共同导致:
- 短连接突增,连接创建速度远大于过期速度。
- 客户端没有复用连接,HTTP keep-alive 或连接池配置不合理。
- TCP 连接异常关闭,残留大量
TIME_WAIT、CLOSE_WAIT或未完成握手状态。 - UDP 流量很多,例如 DNS、日志、监控打点。
- Docker 或 Kubernetes 节点承担大量 NAT 流量。
nf_conntrack_max配置过小,和机器内存、实际连接规模不匹配。- conntrack 相关超时时间过长,旧连接释放太慢。
快速确认是否命中
1. 查看当前 conntrack 使用量
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
第一行是当前已使用条目数,第二行是最大条目数。也可以合并查看:
printf "count=%s max=%s usage=%s%%\n" \
"$(cat /proc/sys/net/netfilter/nf_conntrack_count)" \
"$(cat /proc/sys/net/netfilter/nf_conntrack_max)" \
"$(( $(cat /proc/sys/net/netfilter/nf_conntrack_count) * 100 / $(cat /proc/sys/net/netfilter/nf_conntrack_max) ))"
关键判断:
- 使用率长期超过 70%,需要关注。
- 使用率超过 90%,高峰期很容易触发丢包。
- 使用率接近 100%,并且
dmesg有table full,基本可以确认。
2. 查看内核丢包日志
dmesg -T | grep -E "nf_conntrack|conntrack.*full"
如果输出中有:
nf_conntrack: table full, dropping packet
说明问题已经从容量风险变成实际丢包。
3. 使用 conntrack 工具统计状态
如果系统已安装 conntrack-tools:
conntrack -S
conntrack -L -p tcp 2>/dev/null | awk '{print $4}' | sort | uniq -c | sort -nr | head
常见字段说明:
entries:当前连接跟踪条目数量。searched:查询次数。found:命中次数。insert_failed:插入失败次数,这个值增加时要重点关注。- TCP 状态统计可以帮助判断是正常高并发,还是某类异常状态堆积。
4. 没有 conntrack 工具时的替代方法
很多生产环境没有预装 conntrack 命令,可以直接读 /proc:
awk '{print $4}' /proc/net/nf_conntrack 2>/dev/null | sort | uniq -c | sort -nr | head
如果路径不存在,可能在旧内核上是:
awk '{print $4}' /proc/net/ip_conntrack 2>/dev/null | sort | uniq -c | sort -nr | head
还可以统计访问最频繁的目标:
awk '
{
for (i=1; i<=NF; i++) {
if ($i ~ /^dst=/) dst=$i
if ($i ~ /^dport=/) dport=$i
}
if (dst && dport) print dst, dport
}' /proc/net/nf_conntrack 2>/dev/null | sort | uniq -c | sort -nr | head
这可以帮助判断是某个外部依赖、DNS 服务、数据库代理还是内部服务制造了大量连接。
定位示例
假设当前主机是 Kubernetes Node,业务高峰时出现接口超时。先看使用率:
count=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
max=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
echo "$count / $max"
输出:
259800 / 262144
使用率已经达到 99%。继续看内核日志:
dmesg -T | tail -n 100 | grep -i conntrack
输出:
[Wed Jul 22 09:42:11 2026] nf_conntrack: table full, dropping packet
再看条目分布:
awk '{print $1,$4,$5,$6,$7}' /proc/net/nf_conntrack 2>/dev/null | head
可能看到大量 UDP DNS 请求和 TCP 短连接。如果 DNS 条目明显偏多:
grep "dport=53" /proc/net/nf_conntrack 2>/dev/null | wc -l
如果某个业务外呼端口偏多:
grep "dport=443" /proc/net/nf_conntrack 2>/dev/null | awk '
{
for (i=1; i<=NF; i++) {
if ($i ~ /^dst=/) print $i
}
}' | sort | uniq -c | sort -nr | head
这个结果能把排查方向从“网络不稳定”收敛到“某类目标连接激增”。
临时止血方案
1. 调大 nf_conntrack_max
如果机器内存足够,可以先临时调大:
sysctl -w net.netfilter.nf_conntrack_max=1048576
同时建议调整 hash bucket。该参数通常只能通过模块参数或启动参数设置,不一定能在线修改:
cat /sys/module/nf_conntrack/parameters/hashsize
经验上,hashsize 可以按 nf_conntrack_max / 4 估算。不同发行版配置方式不同,需要结合启动方式处理。
注意:调大上限只是止血,不是根因修复。conntrack 条目会占用内存,不能无限增大。
2. 缩短部分超时时间
高短连接场景可适当调小 TCP 已关闭、等待类状态的超时:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=30
UDP 场景,例如 DNS 请求过多,可以关注:
sysctl -w net.netfilter.nf_conntrack_udp_timeout=15
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=60
不要盲目把超时时间调得过低。过低可能导致长连接或慢请求中途失去跟踪状态,反而制造新的异常。
3. 清理特定异常流量
如果确认某个目标产生了大量异常条目,可以按条件删除。示例:删除目标端口 53 的 UDP 条目:
conntrack -D -p udp --dport 53
删除操作有风险,可能影响正在进行的请求。生产环境建议只在明确异常、业务可接受短暂重试时执行。
根因治理方案
1. 应用侧复用连接
大量短连接是最常见根因。应用需要检查:
- HTTP 客户端是否启用了连接池。
- keep-alive 是否被代理或服务端提前关闭。
- 连接池最大连接数、空闲连接数、超时时间是否合理。
- 是否每个请求都新建客户端对象。
以 Python httpx 为例,不建议每次请求都创建 Client:
import httpx
limits = httpx.Limits(max_connections=200, max_keepalive_connections=50)
timeout = httpx.Timeout(connect=2.0, read=5.0, write=5.0, pool=2.0)
with httpx.Client(limits=limits, timeout=timeout) as client:
response = client.get("https://api.example.com/v1/orders")
response.raise_for_status()
关键点:
max_connections控制总连接数,避免无限并发打爆下游和本机。max_keepalive_connections保留可复用连接,减少短连接创建。pool超时能暴露连接池耗尽,而不是把问题伪装成慢请求。
2. 减少不必要的 NAT
在 Kubernetes 或容器环境中,NAT 会增加 conntrack 压力。可以评估:
- 集群内访问是否可以走 ClusterIP 或服务发现,避免绕外部网关。
- 大流量服务是否需要独立节点、hostNetwork 或专用网关。
- 出口流量是否集中到少数 NAT 节点,是否需要水平拆分。
- kube-proxy、CNI、Service 拓扑是否导致不必要的跨节点转发。
3. 对异常来源限流
如果是某个客户端、任务或定时脚本制造连接风暴,应该从源头治理:
ss -tan state syn-sent | awk '{print $4,$5}' | sort | uniq -c | sort -nr | head
ss -tan state established | awk '{print $4,$5}' | sort | uniq -c | sort -nr | head
结合应用日志确认调用方后,可以做:
- 调整并发。
- 加入退避重试。
- 限制定时任务批量大小。
- 对高频失败请求增加熔断。
- 修复连接未关闭或客户端重复初始化问题。
持久化配置
确认参数后写入 sysctl 配置:
cat >/etc/sysctl.d/99-conntrack.conf <<'EOF'
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30
net.netfilter.nf_conntrack_udp_timeout = 15
net.netfilter.nf_conntrack_udp_timeout_stream = 60
EOF
sysctl --system
再次确认:
sysctl net.netfilter.nf_conntrack_max
sysctl net.netfilter.nf_conntrack_tcp_timeout_time_wait
如果需要配置 hashsize,可以在模块加载配置中处理:
echo "options nf_conntrack hashsize=262144" >/etc/modprobe.d/nf_conntrack.conf
该配置通常需要重载模块或重启后生效。生产环境不要直接卸载 nf_conntrack 模块,因为 Docker、Kubernetes、防火墙、NAT 可能正在依赖它。
监控和告警
建议至少采集两个指标:
nf_conntrack_count:当前使用量。nf_conntrack_max:最大容量。
node_exporter 通常会暴露相关指标,可以在 Prometheus 中查看:
node_nf_conntrack_entries
node_nf_conntrack_entries_limit
告警规则示例:
groups:
- name: linux-conntrack
rules:
- alert: ConntrackUsageHigh
expr: node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "conntrack usage is higher than 80%"
description: "instance={{ $labels.instance }} conntrack usage is above 80% for 5 minutes"
- alert: ConntrackUsageCritical
expr: node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.95
for: 2m
labels:
severity: critical
annotations:
summary: "conntrack usage is higher than 95%"
description: "instance={{ $labels.instance }} may drop new connections"
告警阈值建议:
- 80% 持续 5 分钟:预警,安排扩容或流量分析。
- 95% 持续 2 分钟:严重,可能已经影响新连接。
- 如果
insert_failed持续增加,应按故障处理。
预防措施
- 高并发服务默认开启连接池,避免每次请求新建连接。
- 网关、Node、NAT 实例按峰值连接数评估 conntrack 容量。
- 定期检查内核日志中的
nf_conntrack: table full。 - 对 DNS、HTTP 回调、日志上报等短连接来源做并发控制。
- Kubernetes 节点把 conntrack 使用率纳入基础监控。
- 变更 NAT、Service、Ingress、CNI 配置后观察 conntrack 曲线。
- 压测时不仅看 QPS 和延迟,也看连接数、端口数、conntrack 使用率。
总结
conntrack 表满的典型误导点在于:系统资源看起来正常,但网络请求却随机失败。排查时可以按“内核日志确认丢包、查看 count/max 使用率、分析协议和目标分布、定位异常来源、再决定扩容或治理”的顺序推进。
临时处理可以调大 nf_conntrack_max、缩短部分超时、清理异常条目;长期治理必须回到连接复用、NAT 架构、客户端并发、监控告警上。只调内核参数不处理短连接风暴,问题往往会在下一次流量高峰再次出现。
Discussion
评论