物理主机连接跟踪表耗尽:定位丢包并验证容量调整

物理主机连接跟踪表耗尽:定位丢包并验证容量调整

业务出现间歇性连接超时,已有会话却继续传输,应用进程与监听状态也正常,此时应检查 Linux 的连接跟踪表。状态防火墙、地址转换和部分容器网络依赖 conntrack;表项无法建立时,新流量可能在抵达应用前被丢弃。本文以 Debian 12 为例,按取证、归因、容量调整和回滚组织操作,不改防火墙规则,也不清空现有连接。

一、先确认故障发生在哪个网络空间

CloudDDR 物理主机提供 AMD EPYC 7543P、128GB 或 256GB ECC 内存,但内存容量并不直接决定 conntrack 上限。系统内核、网络命名空间和业务流量才是检查对象。付款后在控制台查看凭据,通过 SSH 接入;多个地址时使用第一个地址。

在实际处理流量的网络命名空间执行命令。宿主机上的结果不能代表客体系统;容器流量若经过宿主机地址转换,需要同时检查宿主机。先记录内核版本、当前网络空间、表项数量与上限:

uname -r
readlink /proc/self/ns/net
sudo sysctl net.netfilter.nf_conntrack_count
sudo sysctl net.netfilter.nf_conntrack_max
sudo sysctl net.netfilter.nf_conntrack_buckets

若键不存在,说明当前空间没有暴露相应参数,不能直接判为耗尽。先确认相关模块是否加载,以及业务是否使用连接跟踪,不要为“补齐输出”在故障期间临时启用新功能。

不执行 conntrack -F。清表会删除跟踪状态,可能破坏现有会话和地址转换映射,也会抹掉定位问题所需的现场。

二、用计数增量建立证据链

安装用户态工具不会改变已有规则,但安装应遵循现有变更流程。以下操作读取现场,并用两个间隔样本判断计数是否继续增长:

sudo apt-get install conntrack
umask 077
sudo conntrack -S > /tmp/conntrack-before.txt
sudo journalctl -k --since "-10 min" --no-pager \
  | grep -Ei 'nf_conntrack|table full'
sleep 30
sudo conntrack -S > /tmp/conntrack-after.txt
diff -u /tmp/conntrack-before.txt /tmp/conntrack-after.txt

conntrack -S 通常按 CPU 输出累计计数。应对照相同 CPU 行,关注 insert_failed、drop、early_drop 的增量,而非把启动以来的数值当成当前故障。计数含义与输出字段可能随内核变化,插入失败也不全是容量不足。

同时记录业务超时数量、表项占用和内核日志。占用接近上限、失败计数增长且业务错误同步出现,才形成较完整的证据链。日志没有匹配结果也不能排除问题,日志可能受限速影响。采样间隔中的短峰值可能被漏掉,必要时缩短观察间隔,但不要循环导出整张表。

三、区分连接数量与连接创建速率

从样本判断表项为何积累

表项数量不等于当前请求数。一条 TCP 连接可以承载多个请求,UDP 也会占用跟踪条目;通信结束后,条目可能继续保留到相应超时。因此,应区分长期稳定连接、短连接突增和异常来源。

可做一次有界抽样,避免在高负载期间反复输出完整连接表:

sudo timeout 5s conntrack -L -o extended 2>/tmp/conntrack-sample.err \
  | head -n 200 > /tmp/conntrack-sample.txt

该命令只取有限输出,可能提前结束并产生非零退出状态,样本不是完整统计。文件包含地址信息,应限制读取权限,工单附件按需脱敏。输出包含原方向与回复方向元组,分析来源时不要把两组地址混算。

检查协议、TCP 状态、剩余超时和原方向来源。大量短连接应结合应用连接池与重试日志检查;少数来源持续创建新流应结合访问记录判断;UDP 条目长期积累则需核对真实通信周期。不能只凭一个状态名称认定攻击,也不要把流量异常简单包装成容量问题。

若连接创建速率没有下降,扩大表只能延后再次触顶。修复无界重试、恢复连接复用或处理异常来源,往往需要与容量调整分别验收。

四、评估内存后只调整一个变量

上限不是预分配内存,也不是吞吐承诺

增加 nf_conntrack_max 不会立即创建全部条目,但持续填表会消耗内核内存。使用 free -h、/proc/meminfo 和 sudo slabtop -o 观察内存及 slab;其中缓存对象大小不能覆盖扩展字段、分配开销等全部成本,不宜套用固定“每连接多少字节”的公式。

nf_conntrack_buckets 是哈希桶数量,不是连接容量。只增上限可能增加桶链长度及查找成本,需同时观察 CPU 与业务延迟;桶数量能否在线修改受内核与命名空间约束,本次不联动修改。

下面仅演示目标上限为 262144 的临时变更。执行前必须确认该值高于现值、内存预算允许,且另一个管理会话可用;它不是适用于所有机器的推荐值。命令在具有管理权限的 shell 中执行:

sudo -i
OLD=$(sysctl -n net.netfilter.nf_conntrack_max)
test "$OLD" -lt 262144 || exit 1
umask 077
printf '%s\n' "$OLD" > /run/conntrack-max.before
sysctl -w net.netfilter.nf_conntrack_max=262144
sysctl -n net.netfilter.nf_conntrack_max

保留原值后,重复同样的业务探测与计数采样。不要同时缩短 TCP established 超时:空闲长连接可能仍被业务使用,全局缩短超时会引入新的断连原因。

五、验收、回滚与持久化分开进行

验收至少覆盖原故障流量及空闲后恢复通信的长连接。检查新连接成功率、失败计数增量、占用增长趋势、内存余量、CPU 和业务延迟。仅看到上限变大,不算问题解决。

若内存压力、CPU 或延迟恶化,使用保存值回滚:

sudo sysctl -w \
  net.netfilter.nf_conntrack_max="$(sudo cat /run/conntrack-max.before)"

降低上限不会立即清除现有条目;若占用仍高于恢复后的上限,新条目的建立可能继续受阻,需要等待条目自然退出并处理流量来源。不要为加速恢复而清表。

临时调整通过后,再检查 /etc/sysctl.conf 与 /etc/sysctl.d/ 中是否已有同名设置,避免多个文件互相覆盖。将经过验收的值写入受版本管理的专用配置文件,例如:

net.netfilter.nf_conntrack_max = 262144

只加载该文件并复查实际值,不在故障期间批量重载无关参数。后续受控重启还应验证模块加载后的最终值,因为文件写入不等于启动时必然生效。

最终记录应包含流量来源、变更前后计数、业务探测、内存观察、原值和恢复步骤。连接跟踪容量治理的完成标志,是故障证据能够解释、调整结果能够复现,而不是表项上限出现一个更大的数字。

常见问题

连接跟踪表接近上限,就能认定它导致了丢包吗?

不能。需要把占用情况与同一时间段内的 insert_failed、drop 或 early_drop 增量、内核日志及业务失败对应起来。单次占用高只能说明容量压力,不能单独证明故障原因。

提高 nf_conntrack_max 后,是否也要缩短 TCP 超时?

不需要联动修改。先保留协议超时,只调整经过内存预算验证的表项上限。全局缩短 TCP established 超时可能破坏空闲长连接;只有明确识别流量模式并完成业务验证后,才考虑单独调整超时。

AMD EPYC 7543P 独享物理主机,$447/月起。

物理主机配置,从内存档位开始

AMD EPYC 7543P,128GB 与 256GB DDR4-3200 ECC 两档。