线上接口偶发超时,最后发现是 conntrack 打满:一次网络故障排查实战

网络故障排查:Linux conntrack 表满导致接口超时

凌晨一点,业务系统中出现了一部分用户访问接口时的504错误。应用日志未见明显异常,Nginx 仅记录少量 upstream timeout 日志;监控显示 CPU、内存和磁盘资源均处于正常水平,并且容器也未发生重启现象。然而,问题并未大规模爆发而是以偶发超时的形式出现。

这类故障往往容易被误判为应用层问题,但实则根源可能在于连接建立和转发路径上的网络问题。最终我们发现,Linux 节点的 conntrack 表被打满导致新连接无法正常建立,从而引发接口超时现象。

本文将依照实际排查步骤进行详细拆解,并重点探讨故障识别、抓包验证、关键指标分析以及修复措施等内容。

一、合理描述故障

在初步探究过程中,需要先明确以下几点:

  1. 确定超时发生在连接建立的哪个阶段。
  2. 是某个特定实例出现问题还是整个网络层存在异常。
  3. 是否存在明显的协议层特征表现出来的问题请求。

这些问题的答案将直接影响后续排查的方向,例如是否需要关注应用线程池、GC、SQL等问题,或者转向 NAT、连接跟踪、队列和丢包等网络层面的诊断。

二、基础面排查

在确认主机层可能存在异常的情况下,请先执行以下命令以检查系统状态:

uptime
ss -s
netstat -s
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count

如果 nf_conntrack_count 接近于 nf_conntrack_max,则说明 conntrack 表接近满载。在 NAT、Kubernetes Service 转发和容器网络等场景中,conntrack 机制至关重要,在表打满后,新的连接请求可能被丢弃或无法正确建立。

一个典型的现场情况可能是:

$ cat /proc/sys/net/netfilter/nf_conntrack_max 
262144

$ cat /proc/sys/net/netfilter/nf_conntrack_count
261981

尽管看起来并不满载,但在突发流量高峰时刻,conntrack 表可能在几秒内达到最大值。此时可通过查看内核日志进一步确认:

dmesg -T | grep -i conntrack

如果看到类似以下的错误信息,则可基本确定问题所在:

nf_conntrack: table full, dropping packet

此信息表明连接跟踪表已满,开始丢弃数据包。

三、偶发超时原因分析

conntrack 表打满后,并非所有现存连接都会瞬时断开。相反,更多情况下是新建立的连接受到影响,导致部分请求出现超时现象。具体表现如下:

  1. 长连接业务仍能正常运行;
  2. 某些重用连接的请求依然能够成功响应;
  3. 高频率的新建连接接口更容易触发超时问题。

以上特征使得故障在业务端看起来像是“短暂抖动”,而不像完全宕机。

如果服务间大量使用短连接,或者上游网关到后端未能有效复用连接,则可能导致问题迅速放大并扩散。

四、抓包定位

面对此类网络问题,正确的做法是围绕关键的连接建立过程进行分段抓包。首先,在异常节点或网关上执行以下命令:

tcpdump -i any host 10.0.12.34 and port 8080 -nn -tttt -vv -c 200

通过对特定接口的抓包,可以更精准地定位问题。如果问题是发生在连接建立阶段,则会看到以下几种可能模式:

1)仅有 SYN 包,后续无 ACK

10:11:02.101 client > server: SYN 
10:11:03.105 client > server: SYN 
10:11:05.110 client > server: SYN 

通过以上步骤,我们可以逐步深入到故障的具体原因,并采取相应的修复措施。

五、深入分析连接结构

仅仅看到 conntrack_count 高度并不足以全面了解问题所在。进一步的诊断需要考虑具体是谁占用了这些资源,以及占用的原因是什么。

从连接状态和来源分布入手进行分析:

conntrack -L 2>/dev/null | awk '{print $4}' | cut -d= -f2 | sort | uniq -c | sort -nr | head

此命令会列出连接最多的几个状态。此外,还可以关注 TCP 连接的来源地址分布情况:

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

另一种方法是直接查看 socket 状态,这将有助于识别是否存在大量的短连接或长时间未关闭的连接。

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

如果发现大量 TIME-WAIT、SYN-SENT 或其他状态的短连接,就需要进一步分析业务流量模型和应用行为:

  • 是否有爬虫或任务突然增加请求量?
  • 网关到服务之间的 keepalive 机制是否正常关闭?
  • 某次发布更改可能影响了连接复用配置吗?
  • 使用 Sidecar 或代理的应用是否存在连接数放大的情况?

从技术角度看,conntrack 表满只是表面现象。真正的问题往往在于连接模式的失衡和失控

六、触发故障的根本原因

回顾故障发生前的一些变更发现,在前一天为了“增强隔离性”,某个上游组件把连接池策略调整得更为保守,导致到后端服务的短连接数显著增加;叠加晚高峰流量,节点上的 conntrack 占用迅速冲高。

与此同时,默认的超时时间较长,旧状态的回收不够快。这些因素共同作用,形成了经典组合拳:

  • 短连接暴增
  • 旧连接回收慢
  • conntrack 表接近上限
  • 新连接建立失败
  • 网关表现为偶发504/上游超时

从事故复盘来看,这并不是单一的 bug。流量模型变化、内核参数上限和连接复用不佳是共同触发故障的原因

七、即刻应对措施

在紧急情况下采取行动的原则是先恢复服务,再进行优化。

1)临时提高 conntrack 上限
sysctl -w net.netfilter.nf_conntrack_max=524288

这可以快速缓解新连接被拒的问题。但需要注意的是这只是暂时的解决方案,并不能从根本上解决问题。

2)检查并优化超时参数

不同的协议和流量模型下,需要调整不同的超时配置。

sysctl net.netfilter.nf_conntrack_tcp_timeout_established
sysctl net.netfilter.nf_conntrack_tcp_timeout_time_wait

如果发现超时时间过长且业务是高频短连接,则可能造成表项堆积。

3)恢复连接复用

确保 Nginx upstream、应用 HTTP 客户端和 RPC 框架的连接池没有被误伤。很多时候,“看起来像网络问题”的事故其实是上层配置不当导致的。

4)必要时进行流量控制

当连接表已接近危险线,临时限流或熔断低优先级任务比硬扛更合理。不要把生产环境当作压力测试平台,这会增加值班同学的压力。

八、长期监控方案

建立有效的监控机制是预防此类故障的关键。

  • nf_conntrack_count / nf_conntrack_max
  • 新建连接速率
  • TCP 各状态分布(特别是 SYN-RECV 和 TIME-WAIT)
  • RST、重传率和丢包率
  • 网关 499/502/504 比例
  • 上游连接池复用比率、空闲连接数以及建连耗时

告警条件应更加精准:

  • 五分钟内增长速度异常
  • 高峰期持续接近上限
  • 特定节点的指标显著高于集群其他节点

这样可以在问题爆发前就提前介入处理。

九、实战排查流程建议

当遇到类似“偶发超时且应用日志无明显错误”的情况,可以参考以下顺序进行排查:

  1. 确认故障影响范围:实例级别、节点级别还是全链路级别?
  2. 查看网关日志判断问题是在建立连接阶段还是在上游处理过程中。
  3. 在异常节点检查 conntrack_count/max 指标。
  4. 通过 dmesg 是否存在“表满,丢弃包”的信息。
  5. 使用 tcpdump 抓取三次握手过程的包确认是否卡在这个步骤上。
  6. 利用 ss -s 和 ss -ant 查看连接状态结构和分布情况。
  7. 回顾近期变更:重点是连接池、代理配置、超时设置等。
  8. 采取先止血再优化的原则进行操作。

这种顺序可以确保快速缩小问题范围,然后深入分析具体细节。不会一开始就陷入某个局部的细节中无法自拔。

十、最后总结

网络故障排查中最忌讳两种情况:只看应用日志和抓包但没有明确假设。 真正高效的排查方法不仅需要记住命令,更重要的是理解每一步操作的目的与验证内容。 此次事故的核心教训就是:“偶发超时不等于应用程序自身出现问题;很多时候是由于网络状态表先达到极限了。” 对于稳定性、链路观测或网络分析的日常巡检及故障复盘工作,选择合适的流量可观测工具会非常有帮助。