物理主机新连接失败,如何判断 conntrack 是否耗尽?

物理主机新连接失败,如何判断 conntrack 是否耗尽?

业务进程正常、已有长连接还能传输,新请求却间歇超时,这类现象不一定来自应用监听队列。物理主机承担状态防火墙或网络地址转换(NAT)时,Linux 的连接跟踪表也可能成为瓶颈。排查重点是把失败时刻、表占用与内核计数对齐,而不是看到连接多就直接扩大上限。

本文以 Debian 13 为例,所有检查在宿主的网络命名空间执行。CloudUDP 机器付款后在控制台查看凭据,Linux 通过 SSH 接入;多个地址时使用第一个地址连接。以下操作不修改网络规则,也不清空现有连接状态。

一、确认故障经过连接跟踪路径

连接跟踪(conntrack)记录通信流的协议、地址、状态与超时,供状态匹配和 NAT 使用。一条业务连接不等于一个应用线程,表项还可能在应用关闭连接后保留一段时间。短连接密集创建、异常扫描或转发负载,都可能推高占用。

先安装检查工具并读取配置:

sudo apt-get update
sudo apt-get install conntrack
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
sudo conntrack -S
sudo nft list ruleset

规则中出现 ct state 或 NAT,是需要关注跟踪容量的线索,但没有这些规则也不能证明完全不跟踪。若读取参数提示不存在,应先确认模块和实际流量路径,不为“补齐输出”盲目加载模块。

容器内的结果不能直接代替宿主结果。宿主转发和容器内部可能经过不同命名空间,必须记录命令执行位置;否则容易用容器的低占用解释宿主的丢包。

不执行 conntrack -F 作为常规恢复手段。清表会移除既有状态,可能破坏依赖状态匹配或 NAT 的会话,还会让原本需要保留的现场证据消失。

二、采集同一时间段的占用与错误增量

nf_conntrack_count 是当前表项数,nf_conntrack_max 是容量上限。接近上限说明余量减少,却不能单独证明请求因此失败。conntrack -S 按处理器输出统计,应逐项求和并比较两次采样的差值,不把某一行当作整机总量。

umask 077
out=$(mktemp -d /var/tmp/ct-check.XXXXXX)
for sample in 1 2; do
  {
    date -Is
    sysctl net.netfilter.nf_conntrack_count
    sysctl net.netfilter.nf_conntrack_max
    sudo conntrack -S
  } > "$out/sample-$sample.txt"
  if [ "$sample" -eq 1 ]; then
    sleep 10
  fi
done
sudo journalctl -k --since "-10 min" --no-pager \
  > "$out/kernel.txt"
printf '%s\n' "$out"

这里的采样间隔只是操作示例,应覆盖业务失败发生的时段。重点关注 insert_failed、drop、early_drop 是否持续增加,以及内核是否出现连接表满的提示。字段随内核版本可能不同,不能因缺少某个字段就认定系统正常。

同时保存应用的新连接失败数、请求量与错误原文。若机器刚重启,累计计数的基准已经变化;不要把重启前后的数值直接相减。低峰时错误计数不再增加,也不代表高峰容量已经通过验收。

三、判断表项为何积累

先区分“正常并发增长”和“异常创建速度”。对照入口请求、应用主动建立的外连、转发业务及连接复用情况。大量短连接即使存活时间不长,也会因创建速率高而积累;长连接则更依赖真实并发规模。

避免把全表导出当作第一步

繁忙主机上,完整列举表项本身会增加排查开销,输出还包含通信地址。先读汇总计数,确有需要再限制协议和输出规模:

sudo timeout 5s conntrack -L -p tcp -o extended 2>/dev/null \
  | head -n 100

这段输出只是有偏样本,不是状态分布统计。超时或管道提前关闭也可能使命令非零退出,不能据此判断表损坏。地址记录只保存在受限目录,提交工单前先移除无关业务信息。

还应同步检查监听进程、应用错误和上游响应。若占用有余量、相关计数没有增长,应转向应用阻塞、路由或其他丢包位置,不继续围绕 conntrack 调参。

不要先缩短全部协议的超时。超时决定空闲连接状态保留多久,过度压缩可能影响长连接;连接池未复用、失败重试失控等问题,应在调用方修复。

四、按内存预算实施可回退变更

扩大上限只是允许更多表项存在,并不修复异常流量来源。表项消耗内核内存,具体开销受协议扩展、内核配置等影响,不能用固定“每条若干字节”计算精确预算。

变更前记录 free -h、/proc/meminfo,并用 sudo slabtop -o 观察内核对象缓存。Slab 是内核用于管理对象的缓存机制;其中的连接跟踪对象统计也不是全部相关内存成本。

若证据支持容量不足,且内存有余量,可用小步调整验证。以下将原上限增加四分之一,仅为试验幅度,不是推荐固定配置:

old=$(sysctl -n net.netfilter.nf_conntrack_max) || exit 1
case "$old" in
  ''|*[!0-9]*) exit 1 ;;
esac
new=$((old + old / 4))
printf 'old=%s new=%s\n' "$old" "$new"
sudo sysctl -w net.netfilter.nf_conntrack_max="$new"

保留该会话和原值,在相近请求量下重新采样。失败没有改善时,不连续加大参数;恢复原值并检查其他证据:

sudo sysctl -w net.netfilter.nf_conntrack_max="$old"

回退前核对当前占用,若已超过原上限,应先降低新增连接压力,否则回退可能再次触发容量问题。不要同时调整哈希桶、协议超时和防火墙规则,避免失去单变量验证条件。

五、用业务结果决定是否持久化

验收必须同时满足三类证据:相近业务量下新连接成功率恢复,相关错误计数不再持续增长,内存与内核对象缓存没有出现新的压力。只有占用率下降,不能算修复完成。

确认有效后,将已验证的数字写入 /etc/sysctl.d/90-conntrack-capacity.conf。写入前检查其他配置文件是否重复定义同一参数,避免加载顺序覆盖。只加载本次文件,不顺带应用整机其他未验证配置:

sudo sysctl -p /etc/sysctl.d/90-conntrack-capacity.conf
sysctl net.netfilter.nf_conntrack_max

文件应包含一行 net.netfilter.nf_conntrack_max = 已验证的整数,其中说明文字必须替换为实际数字。下一次由运维安排的重启后,再核对生效值与加载错误,不为验证参数立即重启生产机器。

最后留存原值、新值、采样区间、请求量、计数差值和回退条件。连接跟踪容量治理的终点不是更大的数字,而是能解释连接失败、能证明变更有效,并能在负载变化后重新检查同一组证据。

常见问题

conntrack 占用接近上限,是否就能认定发生了耗尽?

不能。应结合相同时间段内的 insert_failed、drop、early_drop 计数增量、内核日志和业务新连接错误判断。占用率高只是容量风险信号,单项计数也不能独立确定根因。

能否通过清空 conntrack 表快速恢复业务?

不应把清表作为常规恢复手段。清空会移除现有连接的跟踪状态,可能破坏依赖状态匹配或 NAT 的会话。应先留存计数与日志,再处理异常连接来源或实施有内存预算的容量调整。

EPYC 7543P 独享物理主机,$454/月起

物理主机按月整机出租

配置项与本期应付在结账前核对,所有价格以美元结算。