当"网络有问题"变成一句无法定位的废话
站长排障时最头疼的一类问题,就是"网络有问题"。用户说"你网站好慢""有时候打不开""下载文件总是传一半断了",但你登上服务器一看,CPU 不高、内存充足、磁盘空闲、Nginx 日志里也没有 5xx。ping 网关通、curl 首页也返回 200。于是你陷入一种尴尬:所有指标都正常,但现象确实存在。
这类问题的答案,往往藏在网卡收发的数据包里——它们不在应用日志里,也不在系统指标里。而能让你"看见"这些包的,就是 tcpdump。这篇文章不讲 tcpdump 的几百个参数,只讲站长真正会用到的几个场景:确认丢包、定位重传、抓一次完整的握手、以及怎么在抓包的同时不把服务器打挂。目标很明确——把"网络慢"从玄学变成一个能指着数据说清楚的结论。
先装上,并把权限收好
# Debian/Ubuntu
apt update && apt install -y tcpdump
# CentOS/RHEL
yum install -y tcpdump
# 查看可抓的网卡
tcpdump -Dtcpdump -D 会列出所有网卡,比如 eth0、ens18、lo。务必先用它确认网卡名,现在很多云主机网卡叫 ens3、enp1s0 而不是 eth0,抓错网卡会让你以为"一个包都没有",白白怀疑人生。
抓包需要 CAP_NET_RAW 权限,所以得用 root 或 sudo。一个安全上的小建议:抓包文件可能包含明文 Cookie、Authorization 头,别随手扔在 /tmp 里长期放着,用完及时删。
核心一:确认到底有没有丢包和重传
网络慢的元凶,八成是丢包引发的 TCP 重传。抓包的第一步不是看内容,而是看 TCP 的行为。最实用的抓法:只抓某个 IP、某个端口,并且限制数量,别让文件无限涨。
# 抓和某客户端 IP 之间、目标端口 443 的包,最多 100 个,不解析域名(快)
tcpdump -i eth0 -nn -c 100 'host 203.0.113.10 and tcp port 443'参数含义:-i eth0 指定网卡;-nn 表示不把 IP 反查成域名、不把端口查成服务名(这一步在抓包时非常拖速,务必加);-c 100 抓够 100 个包就停。
看输出时,重点不是内容而是 TCP 标志位:
- 出现大量重复的同一序号(seq)的包,通常是重传,说明之前的包丢了或对方没收到 ACK。
- 频繁出现
DUP ACK(重复 ACK),说明对端收到了乱序或缺失,正在催你重发。 - 出现
TCP Retransmission标记(在 tcpdump 里表现为同一方向、相同 seq 的包重复出现),是丢包的铁证。 RST包突然出现,说明连接被强制中断,可能是防火墙、也可能是对端应用主动拒绝。
但肉眼看大量十六进制很累,更好的做法是把包存成文件,用 Wireshark 或 tshark 分析:
# 抓包存文件(-s 0 表示抓完整包,-w 写文件)
tcpdump -i eth0 -nn -s0 -w /tmp/cap.pcap 'host 203.0.113.10'
# 用 tshark 直接统计重传次数(要单独装 tshark 包)
tshark -r /tmp/cap.pcap -q -z io,stat,0,"COUNT(tcp.analysis.retransmission)tcp.analysis.retransmission"tcp.analysis.retransmission 这个过滤字段是定位丢包的利器,tshark 一条命令就能告诉你这份抓包里发生了多少次重传。如果重传率超过 1%~2%,就足以让用户明显感到"卡"。
核心二:抓一次完整的三次握手,看连接建立卡在哪
用户说"有时候打不开",很可能是 TCP 连接建立阶段就卡住了。三次握手是:客户端发 SYN → 服务器回 SYN,ACK → 客户端回 ACK。抓一段看看哪一步缺失:
tcpdump -i eth0 -nn -c 50 'tcp port 443 and (tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0)'这条过滤只抓带 SYN/FIN/RST 标志的包,输出会清爽很多。几种典型现象对应的问题:
- 只看到 SYN,没有 SYN,ACK。 说明请求根本没到服务器,或到了但被防火墙 DROP。检查云安全组、iptables/nftables、以及
netstat -s | grep -i listen里的 listen 队列溢出。 - 客户端反复重发 SYN(间隔 1s、2s、4s 递增)。 典型的 SYN 重传,说明 SYN 或 SYN,ACK 在链路上丢了。若服务器侧能看到 SYN,ACK 发出,问题就在回程链路或中间设备。
- 连接建立后很快出现 RST。 常见于后端进程没在监听、或 Nginx 后端
upstream端口写错、或半开连接被清理。 - SYN 到了但立刻被 RST。 可能是你在用
net.ipv4.tcp_tw_recycle这类已废弃参数(NAT 环境下会误杀),也可能是中间有设备做了拦截。
尤其要注意:如果服务器在一个 NAT 之后,或者你的站走 CDN,看到的源 IP 是 CDN 节点而不是真实用户。抓包前先想清楚这一段链路是谁跟谁在通信,否则会抓到一堆无关连接。
核心三:抓包看应用层内容(谨慎)
有时你要确认的其实是应用层:请求的 Host 头对不对、是不是某个 API 返回了慢响应、POST 数据有没有传全。这时用 -A 把包内容按 ASCII 打印出来:
# 抓 HTTP 的请求行和 Host 头(80 端口明文才行;443 是加密的看不到)
tcpdump -i eth0 -nn -A -s0 -c 20 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'这个复杂的过滤条件意思是"只抓有实际负载的包",能过滤掉纯 ACK 之类的空包,让输出干净。但记住两个前提:
第一,HTTPS 的内容是加密的,-A 只能看到 TLS 握手和密文,看不到里面的 HTTP。想在 443 上分析应用层,要么在服务器本地解密(导入密钥),要么直接看 Nginx 日志,别指望 tcpdump。
第二,抓明文 HTTP 会暴露 Cookie 和登录凭证,抓完立刻删文件、别外传。这也是为什么生产环境能用应用日志解决的就别抓包。
核心四:让 tcpdump 帮你做统计,而不是自己数
抓包分析的最高效方式,是让 tcpdump 直接输出统计摘要。-q 精简输出,配合 -c 和后续的 awk/sort 就能快速看出"谁在跟服务器说话、说了多少":
# 按源 IP 统计包数量,找出流量最大的来源
tcpdump -i eth0 -nn -c 5000 'tcp' -w - 2>/dev/null | \
strings | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq -c | sort -rn | head更实用的场景是排查"谁在刷我"或"是不是被 CC"。抓个几千包,按来源 IP 聚合,瞬间能看出某个 IP 占比异常高。当然,常规的 IP 统计用 Nginx 日志 awk 更快,tcpdump 的独特价值在于——当攻击或异常发生在 Nginx 之前(比如打到四层、或异常握手根本没进应用层)时,只有抓包能看到。
核心五:抓包别把服务器抓挂
这是最重要的一个坑。tcpdump 在大流量下如果不加限制,会:写满磁盘、占满 CPU、产生巨量 I/O,把一个本来只是"有点慢"的服务器直接拖到不可用。几条铁律:
- 永远加
-c限制包数,或者加-w到有配额的分区,配合-G 60 -W 10做循环切割(每 60 秒一个文件,保留 10 个)。 - 过滤条件尽可能精确。 抓
'tcp'全量是高危操作,尽量限定 host、port、甚至方向。 - 加
-s0抓全包会显著增加文件大小和 CPU;在只需要看 TCP 标志位时,加-s96只抓包头就够,省很多。 - 低配 VPS 上抓包务必在低峰期做,或者先在测试机复现。
- 用完立刻
kill掉 tcpdump 进程,别让它默默跑着。查有没有残留:ps aux | grep tcpdump。
一个安全的循环抓包示例(适合长时间蹲守偶发问题):
# 每 60 秒切一个文件,最多保留 20 个,总共约 20 分钟窗口;只抓指定 host
tcpdump -i eth0 -nn -s96 -G 60 -W 20 \
-w /var/tmp/cap_%Y%m%d_%H%M%S.pcap 'host 203.0.113.10 and tcp'
# 记得确认 /var/tmp 所在分区有足够空间
df -h /var/tmp一个真实的排障思路串起来
用户报"下载大文件总在 80% 断"。我的排查顺序是:先看 Nginx access log 里这个请求的 $request_time 和状态码,如果请求正常返回 200 但耗时异常长,怀疑是传输阶段中断;接着在服务器上抓这段连接的包,过滤该用户 IP 和端口,重点看有没有大量重传、有没有中途 RST;如果发现重传集中在大包(大数据段),而小包正常,那基本就是指 MTU/分片问题——大包因为 DF 位被置位且中间链路 MTU 更小而被丢弃,触发 ICMP 黑洞。解决办法是把 MSS 钳制调小(iptables ... -j TCPMSS --clamp-mss-to-pmtu),或者降低网卡 MTU。
整个过程中,tcpdump 提供的是唯一的、第一手的证据。没有它,你只能靠猜;有了它,"网络慢"就变成了"第 47 号连接发生了 12 次重传,全部集中在大包"这样一句可以行动的话。
五个必踩的坑复盘
- 抓错网卡。 云主机网卡名不是 eth0,先
tcpdump -D确认。抓错会以为没流量。 - 忘加
-nn,抓包时还在做 DNS 反查。 又慢又可能因为 DNS 不通而卡住,抓包必加-nn。 - 在 443 端口用
-A想看 HTTP。 TLS 加密,只能看到密文,想看应用层请用日志或导入密钥解密。 - 生产机裸跑 tcpdump 不限量。 磁盘瞬间写满或 CPU 打满,把服务器搞挂。永远加
-c或-G/-W。 - 以为抓包就能解决一切。 抓包是取证,不是万能药。先想清楚"这段链路是谁跟谁",再决定在哪抓、抓什么,否则只会捞回一堆噪音。
tcpdump 是站长工具箱里少数能"看见网络底层真相"的工具。它不需要你成为网络专家,但你得知道它在看什么、以及怎么看。把上面五个核心场景记住:确认丢包重传、看握手卡在哪、看应用层、做流量统计、以及安全抓包——下次遇到"网络慢",你就不再是干瞪眼,而是能手上有据、心里有底。