目录

服务连不上、老丢包?TCP 网络问题到底该怎么排查?

线上服务连不上,或者接口时不时超时,是日常里最磨人的一类问题。

现象看着都差不多,根因可能差出十万八千里:网卡、路由、防火墙、对端进程、甚至自己代码没关连接。瞎猜没用。

这篇就按一套固定的分层顺序,把 TCP 网络问题从下往上捋一遍,每一步配上能直接抄的命令。

为什么要按分层来排查?

TCP 排查的核心思路是分层定位:从物理链路、网络可达、端口连通,一直查到应用层。

这么做的好处是把范围一刀一刀切小,避免一上来就抓包、淹没在几万行报文里。

我自己的习惯是先问三个问题:能 ping 通吗?端口通吗?连接建起来了吗?

这三关过了,剩下八成是应用层的事。

下面按顺序展开。

第一关:基础连通性,ping 和 mtr

先确认网络层能不能到对端。

## 测连通和丢包率,发 20 个包 ping -c 20 192.168.1.100

重点看两个数:丢包率(packet loss)和延迟(time)。

丢包 0%、延迟稳定,说明这层没问题。

如果丢包忽高忽低,或者延迟从几毫秒飙到几百毫秒,那问题大概率在路由路径上。

这时候别用 traceroute,直接上 mtr

它把 traceroute 和 ping 揉一起,能实时看到每一跳的丢包。

## 持续探测 100 个包,按跳显示丢包和延迟
mtr -rwzbc 100 192.168.1.100

看哪一跳开始持续丢包,问题节点基本就锁定了。

有个坑要提醒:中间某一跳显示丢包、但后面的跳又恢复正常,这种通常是那一跳的路由器对 ICMP 限速,不是真丢包,别被它带偏。

只有「从某跳开始一直到终点都丢」才是真问题。

ping 不通不一定代表网络断了。

很多服务器和云主机默认禁掉了 ICMP,ping 不通但 TCP 端口照样能连。

所以 ping 失败时,下一步要直接测端口。

第二关:端口到底通不通?

ping 通了不代表服务能用,端口可能根本没开,或者被防火墙挡了。

## 方式一:nc,-z 只探测不发数据,-v 显示详情
nc -zv 192.168.1.100 3306

## 方式二:telnet,老牌但够用
telnet 192.168.1.100 3306

连上了会提示 succeeded 或者 Connected。如果卡住不动最后超时,常见就两种情况:防火墙/安全组把包丢了(表现为没任何响应),或者对端端口压根没监听。

云服务器尤其要查安全组。

我被这个坑过不止一次——本地 iptables 全放开了,结果是云控制台的安全组没放对应端口,排查半天白费劲。

所以云上服务连不通,先去控制台看安全组入站规则,比在机器里翻 iptables 快得多。

本机防火墙也顺手看一眼:

## 查看当前 iptables 规则
iptables -L -n -v

第三关:连接状态,ss 是主力

端口通了,就该看连接本身的状态了。

ss 比老的 netstat 快很多,现在基本都用它。

## 看所有 TCP 连接、对应进程,-t TCP -a 全部 -n 不解析 -p 进程
ss -antp

## 统计各状态连接数,这条最常用
ss -ant | awk 'NR>1{print $1}' | sort | uniq -c

第二条命令的输出能直接告诉你连接卡在哪个状态上。

TCP 一共有 11 种状态,分别对应三次握手和四次挥手的各个阶段:

状态 含义 出现在
LISTEN 监听端口,等连接 服务端
SYN-SENT 已发 SYN,等回应 客户端握手中
SYN-RECV 收到 SYN 并回了,等 ACK 服务端握手中
ESTABLISHED 连接建好,正常通信 双方
FIN-WAIT-1 主动关闭方发出 FIN 主动关闭方
FIN-WAIT-2 收到对方 ACK,等对方 FIN 主动关闭方
CLOSE-WAIT 收到 FIN,等应用关连接 被动关闭方
LAST-ACK 发了 FIN,等最后的 ACK 被动关闭方
TIME-WAIT 等 2MSL 再彻底关闭 主动关闭方
CLOSING 双方同时关闭 双方
CLOSED 已完全关闭 双方

状态名记不全没关系,实战中真正要警惕的就两个:CLOSE-WAIT 和 TIME-WAIT。

大量 CLOSE-WAIT:八成是代码 bug

CLOSE-WAIT 表示对端已经发了 FIN 要关连接,但你这边的应用一直没调用 close。

换句话说,连接该关没关。

这几乎可以断定是代码问题——比如异常路径里漏写了关闭、连接池没回收、或者 defer 没执行到。

CLOSE-WAIT 堆积久了会耗尽文件描述符,最后报 too many open files,服务直接挂。

看到这个状态数量持续涨,别调内核参数,回去查代码里连接有没有正常关闭。

大量 TIME-WAIT:通常是正常现象

TIME-WAIT 出现在主动关闭连接的一方,它要等 2 倍 MSL(Linux 上默认是 60 秒)才彻底释放,目的是确保对端收到最后的 ACK、并让旧连接的残留报文自然过期。

短连接场景下(比如压测、频繁请求的 HTTP 客户端),TIME-WAIT 多到几万个都正常。

一般不用慌。

如果端口确实被占满了,可以谨慎开启 net.ipv4.tcp_tw_reuse,但别去动那个早就被废弃的 tcp_tw_recycle,它在 NAT 环境下会导致丢包,新内核里已经删掉了。

第四关:抓包,tcpdump 兜底

前三关都正常,问题还在,那就只能抓包看报文了。

tcpdump 是最后一道兜底手段。

## 抓 eth0 上和指定 IP、指定端口相关的包,存到文件
tcpdump -i eth0 host 192.168.1.100 and port 3306 -w cap.pcap

抓完把 cap.pcap 拖到本地用 Wireshark 打开,比在命令行里盯着看舒服十倍。

重点关注几个信号:有没有大量 retransmission(重传,说明丢包)、有没有 RST(连接被对端强制重置)、SYN 发出去有没有回应(没回应就是握手都没成功)。

举个我遇到的真实例子:接口偶发超时,前面几关全正常,抓包才发现是对端在高负载时直接回 RST 把连接踢了。

这种情况光看连接状态和日志根本看不出来,必须抓包。

关键命令一览

排查时按这个顺序往下走,基本不会漏:

阶段 命令 看什么
连通性 ping -c 20 IP 丢包率、延迟
路由丢包 mtr -rwzbc 100 IP 哪一跳开始丢
端口可达 nc -zv IP PORT 端口通不通
连接状态 ss -ant | awk 'NR>1{print $1}' | sort | uniq -c 卡在哪个状态
进程定位 ss -antp 哪个进程占的连接
防火墙 iptables -L -n -v 规则有没有挡
抓包 tcpdump -i eth0 host IP -w cap.pcap 重传、RST、握手

常见问题

ping 不通就一定是网络断了吗?

不一定。

很多服务器默认禁用 ICMP,ping 不通但 TCP 端口能正常连。

判断网络通不通,应该用 nctelnet 直接测目标端口,而不是只看 ping 的结果。

CLOSE-WAIT 和 TIME-WAIT 哪个更危险?

CLOSE-WAIT 更需要警惕。

它几乎都是应用代码没正确关闭连接造成的,堆积会耗尽文件描述符导致服务崩溃,得回去查代码。

TIME-WAIT 大多是短连接的正常现象,由主动关闭方产生,一般不影响服务。

ss 和 netstat 有什么区别,用哪个?

两者都能看连接状态,但 ss 直接读内核数据,在连接数大的机器上比 netstat 快得多,新系统也默认装它。

建议优先用 ssnetstat 在很多新发行版里已经不预装了。

云服务器连不通端口,先查哪里?

先查云控制台的安全组入站规则,再查机器里的 iptables。

云环境下安全组拦截最常见,而且在机器内部看不到任何拦截痕迹(包被云网关直接丢了),所以从控制台查更快。

tcpdump 抓的包怎么分析?

-w 参数把包存成 .pcap 文件,再拖到本地用 Wireshark 图形化分析。

重点看有没有大量重传(丢包)、RST(连接被重置)、以及 SYN 有没有得到回应(判断握手是否成功)。

写在最后

排查 TCP 问题最忌讳一上来就抓包瞎看。

按 ping → 端口 → 连接状态 → 抓包 的顺序走,大部分问题在前两三步就能定位。连接状态这块,记住 CLOSE-WAIT 查代码、TIME-WAIT 多半正常,就够应付日常九成场景了。

这些命令和判断我都是在自己的 Linux 环境(CentOS 7 和 Ubuntu 22.04)上验证过的,不同发行版参数可能略有差异,遇到不一致以你机器上的 man 手册为准。

如果你在排查时碰到了这篇没覆盖到的诡异现象,或者对某个命令有疑问,欢迎在评论区聊聊~~~

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/troubleshoot-tcp-network-issues/

备用原文链接: https://blog.fiveyoboy.com/articles/troubleshoot-tcp-network-issues/