用心打造
VPS知识分享网站

服务器TIME_WAIT太多怎么办?TCP连接排查方法

监控突然显示TCP连接数暴涨,执行 ss 后看到几万个TIME_WAIT,第一反应通常是系统出问题了。网上也能找到不少直接修改内核参数的命令,但TIME_WAIT本身是TCP正常关闭流程的一部分,数量多不等于一定故障。

真正需要回答的是:这些连接由谁主动关闭、连接到哪里、增长速度多快,以及它们是否已经造成端口耗尽、连接失败或资源压力。没有这些证据,只把计数降下来,很可能掩盖应用频繁建连、重试风暴或连接池失效。

下面以常见Linux云服务器为例,命令主要用于读取现场。连接地址可能包含客户IP、内部服务名与业务端口,保存或分享结果时需要脱敏。生产环境不建议直接套用来源不明的sysctl参数。

TIME_WAIT太多

先确认数量、趋势和真实影响

先记录当前时间和TCP状态汇总:

date -Is
ss -s
ss -tan state time-wait | wc -l

ss -s 可以快速看到established、timewait、orphaned等状态数量。单次数字只能表示一个瞬间,最好每隔10秒采样一次,持续几分钟:

for i in $(seq 1 30); do
  printf '%s ' "$(date +%T)"
  ss -tan state time-wait | tail -n +2 | wc -l
  sleep 10
done

这里的 sleep 只适合人工短时采样或放进受控脚本,不要在交互终端忘记停止。持续稳定在某个范围,与从几百快速涨到几万是不同现象;业务高峰后自然回落,也比全天不降更接近正常短连接行为。

同时核对用户是否真的受到影响。重点看应用日志中的 Cannot assign requested address、连接超时、连接被拒绝,以及负载均衡器的后端连接失败。再检查CPU、内存和网络错误。只有TIME_WAIT数量,没有业务失败或资源耗尽证据,不能直接判定需要调内核。

判断服务器是客户端还是服务端

TIME_WAIT通常出现在主动关闭连接的一侧。Web服务器可能对外是服务端,对数据库、Redis、第三方API又是客户端,因此不能看到本机有TIME_WAIT就认定访客连接过多。

先按本地端口和远端端口统计:

ss -tan state time-wait | awk 'NR>1 {print $4}' | sed 's/.*://' | sort | uniq -c | sort -nr | head
ss -tan state time-wait | awk 'NR>1 {print $5}' | sed 's/.*://' | sort | uniq -c | sort -nr | head

IPv6地址含有多个冒号,简单的 sed 统计可能不适合所有输出格式。更稳妥的做法是保留原始结果,再针对已知端口过滤。例如大量连接的远端端口是3306、6379或某个HTTPS接口端口,说明本机应用可能频繁向下游发起短连接。

抽取少量样本查看完整四元组:

ss -tan state time-wait | head -n 50

本地地址一侧是随机高位端口、远端是固定服务端口,通常表示本机是发起连接的客户端;本地是80或443,远端为随机端口,则更像本机Web服务主动关闭外部连接。代理、NAT和容器网络会改变观察位置,结论还要结合部署拓扑。

按目标地址找出连接集中点

接下来统计远端地址与端口,找到最集中的下游:

ss -tan state time-wait | awk 'NR>1 {print $5}' | sort | uniq -c | sort -nr | head -n 20

某个数据库、内部API或第三方服务占绝大多数时,回到应用日志和请求指标,检查连接创建速率、失败率与重试次数。多个目标均匀分布,则可能是爬虫、批量任务、代理转发或正常高并发短连接。

需要把连接归到进程时,TIME_WAIT套接字通常已经没有持有它的用户进程,ss -p 不一定显示PID。可以在连接仍处于ESTABLISHED时观察进程:

sudo ss -tanp state established
sudo lsof -nP -iTCP -sTCP:ESTABLISHED

再结合应用的连接池指标、请求追踪和访问日志定位。只靠TIME_WAIT阶段反查进程,经常得不到完整答案,这是协议状态与观察时机造成的,不是命令失效。

检查是不是连接池没有复用

应用对数据库、缓存和HTTP下游每次请求都新建TCP连接,会产生明显的TIME_WAIT。查看应用框架的连接池配置,关注池大小、空闲连接数、最大生命周期、keep-alive和连接创建速率。

HTTP客户端还要确认是否复用了会话或客户端实例。把客户端对象创建在每个请求函数内部,常会让连接池刚建立就被销毁。反向代理可检查upstream keepalive配置与上游响应头,但配置方式要与Nginx版本、协议和应用能力匹配。

连接池不是越大越好。池上限超过数据库允许连接数,会把TIME_WAIT问题变成下游连接耗尽;连接长期不淘汰,也可能遇到负载均衡、DNS变更或服务端空闲超时。应该根据并发量、单次查询时间和下游容量设置,并观察连接创建率是否在修改后下降。

排除错误重试和健康检查风暴

下游服务故障时,应用可能立即重试,多个实例同时重试就会迅速放大连接数量。检查故障时间附近是否出现TLS握手失败、认证失败、连接拒绝或5xx。重点观察同一请求在几秒内被重复多少次。

合理的重试应有限次、带指数退避和随机抖动,并只对幂等或明确可重试操作启用。数据库写入、支付或创建资源类请求盲目重试,还可能造成重复数据。健康检查间隔过短、每次都新建连接,也会制造稳定的短连接流量。

最小改动通常是先修复错误目标、证书或鉴权,再调整重试节奏。不要只在内核层允许更多连接,因为那会让错误流量继续冲击下游。

确认有没有临时端口耗尽

本机作为客户端时,每条连接需要一个临时源端口。查看当前范围:

sysctl net.ipv4.ip_local_port_range

再统计某个本地IP到特定目标的连接量。端口是否耗尽与四元组有关,不是TIME_WAIT总数达到某个固定数字就必然出错。应用日志出现 Cannot assign requested address,并且大量连接集中到同一个目标IP和端口,才支持临时端口压力的判断。

还要检查NAT网关、负载均衡器和容器出口。多个实例共用一个NAT地址时,瓶颈可能在外部设备的端口映射表,而服务器自身仍有余量。此时应查看云平台NAT指标、连接跟踪表与错误记录。

扩展临时端口范围属于容量调整,不是根因修复。修改前要确认不会与固定服务端口和安全策略冲突,并在测试环境验证。更优先的方向通常是连接复用、减少无效重试、增加目标地址或合理拆分出口。

不要误改tcp_fin_timeout

常见误区是看到TIME_WAIT后调小 net.ipv4.tcp_fin_timeout。Linux内核文档说明,这个参数控制的是孤立连接在FIN_WAIT_2状态保留的时间,并不是TIME_WAIT的通用计时器。调整它无法按想象直接解决TIME_WAIT。

另一个常见参数是 net.ipv4.tcp_tw_reuse。内核文档明确提醒,不应在没有专家建议时修改。不同内核版本的取值与默认行为也可能不同,现代内核还可能只对回环流量启用。把旧教程中的参数原样写入生产机,可能带来协议兼容和难以复现的连接问题。

已经移除的 tcp_tw_recycle 更不能作为方案。旧内核中启用它会对NAT后的客户端造成严重兼容问题,现代内核通常已不再提供。看到sysctl提示键不存在,不要尝试通过其他模块强行恢复。

用抓包验证谁先关闭连接

连接角色仍不明确时,可以围绕单个目标做短时间抓包:

sudo tcpdump -ni any 'host TARGET_IP and tcp port TARGET_PORT' -c 200

观察FIN与ACK的方向可以辅助判断谁主动发起关闭。抓包还可以发现连接建立后立即关闭、RST重置和重复握手。生产环境要限定目标、端口和包数量,避免生成巨大文件或收集无关业务流量。

需要保存pcap时设置权限与保留时间,文件可能包含连接地址和部分明文协议内容。TLS流量虽然看不到业务正文,仍可能暴露域名、时间和通信关系。

复杂问题在原服务器上难以稳定复现时,可以用 萤光云 建立同版本应用与连接池配置,或在按小时计费的 LightNode 上构造受控请求率。测试环境只使用模拟数据,并限制连接上限,避免对真实下游形成压力。

根据证据选择最小改动

短连接来自正常访问且没有失败,可以先建立基线与告警,不必修改。连接池未复用,就从应用生命周期和keep-alive配置修复;错误重试造成峰值,就限制次数并增加退避;单一目标确实导致端口压力,再评估多目标、出口拆分或端口范围。

每次只改一个变量,并记录修改前的每秒新建连接数、TIME_WAIT峰值、业务错误率和响应时间。一次同时改连接池、重试、内核参数和负载均衡,数值即使下降,也无法知道真正有效的是哪一项。

需要重启应用时先做滚动操作,避免所有实例同时断开并重新建连。连接池参数变更还要确认下游数据库或API能够承受新的并发连接数。

验收必须覆盖原来的高峰

修复后用相同业务场景复测,至少观察一个完整高峰。TIME_WAIT数量不一定降到很低,关键是每秒连接创建率下降、端口余量充足、下游连接稳定,且不再出现连接分配失败。

保存 ss -s 趋势、主要目标地址分布、应用重试次数和连接池指标。重启应用后再次观察,防止配置只在当前进程内临时生效。系统升级或内核变更后也要复核sysctl值,避免历史参数与新内核语义冲突。

最终结论应能说明TIME_WAIT主要来自哪个连接方向、为什么产生、是否造成真实影响,以及哪个最小改动改善了哪些指标。只以数量从几万降到几千作为成功标准并不完整。

常见问题

TIME_WAIT很多会占用大量内存吗?

它会占用一定内核资源,但是否构成压力要看系统规模、连接速率和实际内存。先观察内存、端口与业务错误,不要仅按连接数量判断。

重启服务器能清掉TIME_WAIT吗?

会清掉当时的连接状态,却不会修复频繁建连或错误重试。业务恢复后相同流量会再次产生,重启还会带来额外中断。

服务端看到TIME_WAIT,说明客户端有问题吗?

不一定。TIME_WAIT更常出现在主动关闭的一侧,服务端也可能主动关闭连接。需要看四元组、协议行为和抓包结果,不能只按机器角色判断。

赞(0)
未经允许不得转载;国外VPS测评网 » 服务器TIME_WAIT太多怎么办?TCP连接排查方法
分享到