一次由 tcp_tw_recycle 引发的“灵异”故障排查:基于双网闸架构的踩坑记

一次由 tcp_tw_recycle 引发的"灵异"故障排查:基于双网闸架构的踩坑记

背景

最近在排查一个线上服务的网络连接问题,现象非常"诡异":

  • 服务端和客户端逻辑都没有明显改动。
  • 大部分请求正常,但偶尔会出现连接建立失败、超时。
  • 抓包发现 TCP 握手阶段有异常,部分 SYN 包被直接丢弃,没有回应。
  • 问题不是必现,但一到业务高峰期就零星出现,让人非常头疼。

经过一系列排查,最终定位到是 Linux 老版本内核参数 tcp_tw_recycle 在作祟。修改后,问题立刻消失。

这篇文章记录一下整个排查思路和背后的原理,希望能帮到遇到类似问题的同学。

网络拓扑与问题现象

我们的网络架构比较特殊,采用了双网闸(安全隔离与信息交换系统) 进行内外网隔离,拓扑简化如下:

  • 内网核心 :T:1/3/0/42, VLAN3102,IP 10.10.10.1/24
  • 内-外网闸 (172.16.1.156):
    • 内网业务口 t1/17:10.10.10.2/30
    • 外网链接发起口 t1/17:10.10.20.2/24
  • 外网 AF :
    • eth18:10.10.20.1/24
    • eth19:10.10.30.1/30
  • 外-内网闸 (172.16.1.157):
    • 外网业务口 t1/17:10.10.30.2/30
    • 内网链接发起口 t1/17下:10.10.10.3/24

数据流向 :

内网核心(10.10.10.1)→ 内-外网闸(10.10.20.2)→ 外网 AF(10.10.20.1)→ 外网 AF(10.10.30.1)→ 外-内网闸(10.10.30.2)→ 内-外网闸(10.10.10.2)→ 内网核心(10.10.10.1)。

故障现象 :

在这种双网闸、多段 NAT 的架构下,内网核心访问外网业务时,部分连接会卡在 SYN 阶段,服务端没有回应 SYN-ACK,也没有 RST。客户端重试几次后,部分连接成功,部分彻底失败。

排查过程

1. 初步怀疑:网络抖动?服务端负载?

一开始怀疑是网络抖动或者服务端负载过高。但查看监控:

  • 服务端 CPU、内存、带宽都正常。
  • 网闸设备没有丢包告警。
  • 问题出现在多个客户端,但又不是全部客户端。

2. 抓包分析:SYN 包被丢弃

在内网核心 (10.10.10.1)和外网 AF(10.10.20.1)同时抓包,发现一个关键现象:

  • 内网核心发出 SYN 包。
  • 经过内-外网闸后,源 IP 被 NAT 成 10.10.20.2。
  • 外网 AF 收到 SYN 包,但没有回应 SYN-ACK。
  • 内网核心重试几次后,部分连接成功,部分彻底失败。

这看起来像是外网 AF 或外-内网闸直接把 SYN 包丢了,而不是应用层的问题。

3. 关键验证:关闭 TCP 时间戳后恢复正常

在排查过程中,发现了一个非常关键的验证现象:

  • 如果把内网所有访问该外网服务器的客户端 的 TCP 时间戳(tcp_timestamps)全部关闭,连接完全正常。
  • 但只要其中任意一台服务器重新开启时间戳访问,问题就会再次出现。

这个现象几乎直接锁定了问题根源:不是网络设备丢包,而是服务端内核根据 TCP 时间戳做了某种"过滤"。

4. 聚焦内核参数:tcp_tw_recycle

查阅资料后,怀疑到 tcp_tw_recycle 这个参数。

先确认当前内核版本和参数值:

bash 复制代码
uname -r
# 输出:3.10.0-xxx.el7.x86_64 (老版本内核)

sysctl net.ipv4.tcp_tw_recycle
# 输出:net.ipv4.tcp_tw_recycle = 1

果然,tcp_tw_recycle 被开启了。

什么是 tcp_tw_recycle?

tcp_tw_recycle 是 Linux 内核的一个参数,用于快速回收 TIME_WAIT 状态的 socket。

  • 默认值:0(关闭)

  • 开启后:内核会使用更激进的策略回收 TIME_WAIT,减少端口占用。

听起来很美好,但它有一个致命缺陷:

在 NAT 环境下,tcp_tw_recycle 会导致部分客户端连接被丢弃。

为什么 NAT 环境下会出问题?

  • tcp_tw_recycle 依赖 TCP 时间戳(tcp_timestamps) 来判断连接的新旧。

开启 tcp_tw_recycle 后,内核会记录每个源 IP 的最近时间戳(per-host PAWS)。

  • 如果同一个源 IP 发来的新连接,时间戳 小于 之前记录的最近时间戳,内核会认为这是一个"过时"的包,直接丢弃。

问题来了:

在 NAT 环境下,多个客户端共享同一个源 IP(对服务端而言)。

不同客户端的系统时间戳(TCP TSval)可能不同步(有的快,有的慢)。

如果客户端 A 的时间戳较大,客户端 B 的时间戳较小,B 的 SYN 包就会被服务端判定为"过时",直接丢弃。

在我们的拓扑中:

内网核心(10.10.10.1)经过内-外网闸后,源 IP 被 NAT 成 10.10.20.2。外网 AF(10.10.20.1)作为服务端,看到的所有连接都来自 10.10.20.2。如果内网有多台服务器(或同一客户端多次连接),只要其中一台开启了 TCP 时间戳,并且它的 TSval 比之前记录的更大,就会拉高服务端为 10.10.20.2 维护的"最近时间戳"。之后其他时间戳较小的客户端再发起连接,就会被直接丢弃。

这就是为什么:

问题不是必现,而是部分客户端、部分时间出现。

全部关闭时间戳就正常(服务端不再做 PAWS 校验)。

只要有一台开启时间戳就会出问题(它会"污染"服务端为该 NAT 源 IP 维护的时间戳水位)。

解决方案

修改内核参数,关闭 tcp_tw_recycle:

bash 复制代码
sysctl -w net.ipv4.tcp_tw_recycle=0
永久生效:
bash 复制代码
echo "net.ipv4.tcp_tw_recycle = 0" >> /etc/sysctl.conf
sysctl -p
修改后,问题立刻消失,连接成功率恢复正常。
  • 注意:关闭 tcp_tw_recycle 是根治方案。关闭客户端时间戳只是临时规避手段,且会带来其他副作用(如无法使用 RTTM、PAWS 保护减弱等),不建议作为长期方案。

为什么老版本内核更需要注意?

在 Linux 4.12 之后,tcp_tw_recycle 已经被彻底移除。

但在 CentOS 7、早期 Ubuntu 等老版本内核中,这个参数依然存在,且可能被一些"优化教程"建议开启。

很多运维人员为了减少 TIME_WAIT,会盲目开启 tcp_tw_recycle,结果在 NAT 环境下踩坑。

经验总结

不要盲目开启 tcp_tw_recycle,尤其是在 NAT 环境下。

如果必须优化 TIME_WAIT,优先考虑:

开启 tcp_tw_reuse(相对安全)

调整 tcp_max_tw_buckets

使用长连接

老版本内核升级前,务必检查这个参数。

排查网络问题时,抓包 + 内核参数检查是黄金组合。

在双网闸、多段 NAT 架构下,尤其要注意 TCP 时间戳和 tcp_tw_recycle 的相互作用。

"关闭所有客户端时间戳就正常,开启任意一台就复现" 是 tcp_tw_recycle 在 NAT 环境下引发问题的典型特征,可作为快速定位依据。

  • 参考
    Linux 内核文档:Documentation/networking/ip-sysctl.txt
    RFC 1323:TCP Extensions for High Performance
    关于 tcp_tw_recycle 被移除的 commit
相关推荐
凯基迪科技22 分钟前
瑞萨R5F100解密 R8C/RL78 MCU 固件读取与保护机制详解
服务器·网络·单片机
承渊政道23 分钟前
Linux网络学习【五种IO模型与⾮阻塞IO】
linux·网络·学习·ubuntu·io模型·非阻塞io
code_slave(码畜)41 分钟前
微服务架构落地:慢 SQL 治理与连接池调优 —— 守住数据库的最后一道防线
数据库·spring boot·sql·spring cloud·微服务·架构
未力忘1 小时前
S7-200 SMART Modbus TCP 通信实践
网络·网络协议·tcp/ip
Likeadust1 小时前
说开就开:临时发起的私有化音视频实时通信EasyDSS视频会议,让跨城协作不再“等排期”
网络·音视频·easydss
愤怒火龙果1 小时前
AI攻防 AIRT补充篇|侦察指纹 · 多模态越狱 · Agent 与 MCP 安全
网络·人工智能·ai安全
北邮刘老师1 小时前
智能体手机的成败关键——智能体互联生态
网络·人工智能·智能手机·智能体·智能体互联网
手可摘星陳×1 小时前
10-运维排障篇-无线排障框架与常见故障-诊断矩阵速查
运维·网络
半壶清水2 小时前
[软考网规考点笔记]-局域网之冗余网关技术
网络·笔记·智能路由器
fengci.2 小时前
CTF2困难部分
开发语言·网络·python·安全·php