网络不通、延迟偏高这类问题,几乎每个做开发或者运维的人早晚都得碰上一回。最气人的不是服务挂了,而是服务活得好好的,就是响应慢半拍,或者业务侧一会儿通一会儿断。ping网关通了、ping对端也通,可应用层就像被什么东西卡住了一样。太多排查到最后发现,问题根本不在应用代码,而在链路上某一个不起眼的环节。这个时候,tcpdump 就是最有用的底层取证工具——它能让你看到网络栈里最原始的数据包长什么样、谁丢了、谁重传了、谁时序乱了。下面这套流程,是我做网络排查时反复用的方法,把它拆成三步,照着做基本能快速定位到“罪魁祸首”。
1. 定位之前:先把排查思路理清楚
1.1 网络排查的基本盘:先确认现象再选工具
遇到网络问题,第一反应别急着抓包。先问清楚几个问题:是不通,还是慢?是所有节点都疼,还是只有特定路径疼?是持续性问题,还是间歇性抽风?
我把“不通”和“慢”分开看:
- 完全不通,通常指向链路断、路由问题、防火墙丢弃、ARP 解析失败这几类。
- 通但慢,更复杂一些,可能是拥塞、丢包重传、TCP 窗口太小、MTU 过大导致分片丢失、对端处理能力不足。
- 间歇性异常,大比例是链路质量抖动、负载过高、缓存表项老化、或者某些定时任务引起的瞬时拥塞。
工具选择也要跟着现象走。ping 只能验证三层连通性,telnet/nc 只能验证端口通断,curl 能看到应用层返回,但这些工具都有一个共性:它们只告诉你“结果不行”,不会告诉你“哪个环节不行”。mtr 能测路径,但它发的是 ICMP/UDP 探测包,跟业务真实走的 TCP 流不一样。真正要还原业务数据包到底经历了什么,只有抓包这一个办法。
1.2 为什么是 tcpdump 而不是直接上 Wireshark
很多人问过我这个事:既然 Wireshark 图形界面看得那么清楚,为什么还要用 tcpdump?
原因很现实。线上服务器大多没有图形环境,你也不可能为了排查问题临时给生产机装桌面。tcpdump 是命令行工具,几乎任何有网卡的 Linux 系统上都默认自带,或者一条apt install/yum install就能装上。它能直接在出问题的机器上跑,抓完生成.pcap文件,再拿回本地用 Wireshark 打开做可视化分析。这已经是我习惯的标准工作流了。
另一个关键点是,tcpdump 基于 BPF(伯克利包过滤器)工作,它旁路挂在网卡上监听经过的数据包,不会修改数据、不会影响业务转发。抓包行为本身对网络的影响可以控制得很小,前提是你别乱抓、别全量抓、别在核心链路上无脑长时间抓大流量。
1.3 tcpdump 和 Wireshark 是怎么配合的
我平时用的是这套组合拳:
- 在出问题的主机上用 tcpdump 抓包,保存成文件。
- 把抓到的文件拉到本地 Wireshark 打开,用图形界面里的统计图、流的会话视图、专家提示信息辅助分析。
- 如果手头只有命令行环境,就用
tshark或者capinfos做统计和分析。
这个配合方式的好处在于,抓包环节轻量、性能开销小,分析环节直观、信息全面。尤其是当你看重传、看 TCP 时序、看往返时间 RTT 时,Wireshark 的 IO 图、时间序图比瞪着眼睛盯 tcpdump 终端输出高效得多。
归根结底,tcpdump 负责“取证”,Wireshark 负责“研判”,两者缺一不可。
2. 抓包这一步,决定排查效率
2.1 动手前的基线确认:网卡、时间、规则
抓包不是敲个tcpdump回车就行。我每次都会在抓包前花两分钟确认三件事,省得抓回来才发现数据根本不对。
第一,网卡对不对。机器多网卡的情况太常见了,物理网卡、虚拟网卡、bond 口,错一个网卡啥都抓不到。如果不确定走哪张网卡,可以用tcpdump -D列出所有可用网卡,再配合ip route get <目标IP>看实际出口走哪张。图省事就直接-i any,但这个方式在某些环境下拿不到完整的链路层信息,比如 VLAN tag 在有些驱动上会被剥掉。
第二,时间准不准。抓包分析特别依赖时间戳。排查延迟问题之前先确认系统时间是否准确:date看一下,偏差太大了先同步 NTP。如果两端同时抓包做对比分析,更要确认两台机器时间一致,不然后面的时序对比全是错的。
第三,规则要事先设计好。我建议你按下“抓什么”而不是“能抓到什么”来决定过滤规则。业务走的是 443 端口,就只抓 443;怀疑 DNS 有问题,就只抓 53 端口;怀疑某个 IP 异常,就直接指定host。范围越精确,文件越小,噪声越少,分析越快。
2.2 必背的过滤表达式和参数
tcpdump 的命令参数不复杂,真正用得熟练全靠平时积累。我给你列几个我几乎每次都用的:
# 监听指定网卡,不做 DNS 反解,抓完整包长,保存到文件 tcpdump -i eth0 -nn -s0 -w /tmp/capture.pcap # 抓取指定主机的所有流量 tcpdump -i eth0 -nn host 10.10.10.10 # 抓取指定端口,限定协议和方向 tcpdump -i eth0 -nn tcp port 443 and src host 10.10.10.10 # 同时抓多个端口 tcpdump -i eth0 -nn "tcp port 80 or tcp port 443" # 限定抓取 N 个包后自动停止 tcpdump -i eth0 -nn -c 1000 port 8080几个关键参数单独说下:
-nn:不做域名反解、不显示服务名。反过来讲,不加这个参数,tcpdump 可能因为反解 DNS 导致输出很慢,排障时千万别省这个。-s0:抓全包。默认只抓前 96 字节或 128 字节的头部,做协议分析凑合够,但排查应用数据相关的问题(比如确认包里的协议内容)就必须要全包长。-e:显示链路层信息,看 MAC 地址和 VLAN 时用。排查 ARP、二层环路这类问题,不加这个参数等于瞎抓。-vv / -vvv:输出更详细信息,能看到 TCP 选项、校验和之类的细节。-w写文件、-r读文件。生产环境抓包基本都是写文件,谁会盯着终端看上百行的滚动输出呢。
过滤语法是 BPF 表达式,支持host、src host、dst host、port、src port、dst port、tcp、udp、icmp、less、greater这类关键词,还能用and、or、not组合。注意顺序:先写协议再写信址条件,习惯上tcp port 443 and host 1.2.3.4这样的写法读起来更舒服。
2.3 抓包时长和文件轮转的经验值
新手最容易犯的错,是把抓包开着放在那儿不管,等发现问题去看,磁盘满了,或者文件大到工具都打不开。
我一般根据地规摸设置抓包策略:
- 如果问题持续存在,抓 30 秒到 1 分钟的包基本足够。
- 如果是间歇性问题,一次抓 5 到 10 分钟,循环抓取多个文件,直到捕获到异常窗口。
- 文件大小控制在一个文件 100MB 到 200MB 以内,超过这个量 Wireshark 打开会很吃力。
- 结合
-G(按时间轮转)和-W(保留文件数)参数,实现自动轮转。
举例,每 60 秒生成一个新文件,最多保留 10 个文件:
tcpdump -i eth0 -nn -s0 -G 60 -W 10 -w /tmp/monitor.pcap这样抓下来的文件会自动命名为 monitor.pcap、monitor.pcap1 这种,按时间覆盖,不影响业务,也不会撑爆磁盘。
3. 三步定位法实战拆解
3.1 第一步:按现象圈定抓包范围
抓包范围怎么定,直接决定后面的分析路径。我习惯先判断“从哪个视角看问题”:
- 如果客户端访问服务端失败,先在服务端抓包,看看请求有没有到达。
- 如果到达了但客户端没收到响应,再在客户端抓包,看看回包有没有回来。
- 如果两端都没问题还报不通,那才需要中间链路介入,比如在网关或交换机镜像口抓包。
有条件的情况下,强烈建议同时在两端抓包,时间对齐后做对比分析,这是定位网络问题最有说服力的方式。两边都好端端,数据就是没穿过中间网段的时候,你就知道不是机制性故障,而是网络路径上的问题。
抓包数量的控制也有讲究。不要一上来全量抓包,那会让文件以每秒几十 MB 的速度增长。根据现象缩小范围:端口不通就抓该端口的 TCP 流量;丢包明显就抓 ICMP;怀疑 DNS 就抓 UDP 53。
3.2 第二步:从包特征反推问题点
抓到包之后,看什么很关键。我习惯按照这个顺序逐步筛查:
第一道:看 TCP 握手有没有完成。客户端发 SYN,服务端回 SYN-ACK,客户端再回 ACK,这三步缺了哪一步,问题就在那一环。比如 SYN 发了 N 次,服务端就是没响应,要么服务端没监听,要么防火墙把包丢了;如果服务端回了 SYN-ACK,客户端却一直重发 SYN,大概率是回程路径上回包丢了。
第二道:看有没有重传和重复 ACK。TCP 是靠“确认”保证可靠性的。如果一个包发出去后超时没收到 ACK,发送端会重传,传一次说明有瞬时丢包,频繁重传就说明链路质量有问题。通过 tcpdump 抓到的重传包数量,能估算实际丢包率。
第三道:看延迟的构成。用一个连接的三次握手时间举例,从 SYN 包发出到收到 SYN-ACK 的间隔就是一次 RTT,把它跟正常基线做对比,能大概看出是网络路径长了,还是对端处理慢了。如果来回要 100ms 以上,而你的业务本来应该在同机房跑,那肯定是不正常的。
第四道:看乱序。TCP 会尽量按序号有序递交。如果抓包里出现大量乱序包、乱序到达的 ACK,通常说明路径上存在多条链路负载均衡或者缓冲抖动。
下面的速查表是我自己整理的,分享你直接抄:
| 包特征 | 大概率问题方向 |
|---|---|
| SYN 频繁重传,无响应 | 服务端未监听、防火墙过滤、SYN 包被丢 |
| SYN-ACK 发出但客户端重传 SYN | 回程路由异常、回包被防火墙拦截 |
| 大量 TCP 重传(Retransmission) | 链路丢包、接收窗口耗尽、带宽拥塞 |
| 大量 Dup ACK | 丢包触发快速重传、乱序触发重复确认 |
| 包负载整齐接近 1500 字节时重传 | MTU 设置不合理,可能导致IP分片丢失 |
| ICMP fragmentation needed 频繁 | MTU 不匹配,路径上某些设备不支持大包 |
| 出现大量 ARP 请求 | 网关 MAC 解析异常、ARP 表震荡 |
| RST 包 | 端口未监听、应用主动重置、防火墙干扰 |
3.3 第三步:交叉验证并确认罪魁祸首
包特征只能告诉你“有问题”,要确认“是什么问题”,还得做交叉验证。我的做法是:抓包证据 + 系统状态 + 配置核查三者比对。
举例来说,服务端抓包看到 SYN 到达但应用没有回包,那就去查服务进程还在不在、监听端口有没有被占用:
ss -lntp | grep 443如果监听还在但又没回包,那可能是服务端 accept 队列满了或者内核 SYN cookies 触发后的行为异常,这时就看netstat -s里的相关计数。
如果是路由层面的问题,ip route get <目标IP>会告诉你内核到底选哪条路径走。加上iptables -L -n -v看计数器,能判断包是不是在防火墙规则里被 DROP 了。这里有个小技巧,本来iptables每条规则 DROP 的计数都可能是 0,但等异常窗口过去再看,如果某一条的包计数一直在涨,那基本就是它在捣鬼。
抓包结论不是孤证。我的习惯是,至少要有一个系统层指标、一个抓包特征、一个配置事实互相对应,才敢认定问题根源。
4. 典型场景实录:三个真实案例
4.1 案例一:TCP 重传率飙升,问题出在 MTU
一次线上故障,业务反馈跨机房数据同步慢。我上服务器看了下,ping对端 IP 正常,延迟 5ms 左右,但 TCP 传大文件只有正常速度的三分之一。
在两端分别抓包。客户端抓到的包几乎每 3 到 5 个就有一个重传,服务端抓到的包却看到大量重复的 ACK。进一步看包大小,发现数据包负载全是 1460 字节左右,接近以太网 1500 字节 MTU 的上限。结合之前链路中有一个奇怪的网段跳数异常,我怀疑路径上某个设备的 MTU 比较小。
验证方式:本地ping -M do -s 1472 <对端>(1472 负载加 28 字节 IP+ICMP 头正好 1500),目标 IP 能通。但用同样的方法测试路径上某些中转 IP,返回Fragmentation needed的错误。说明问题在这条中转链路上。
原来客户端和服务端都是标准 MTU,但中间有一个隧道设备把 MTU 限制到了 1400。大包到那儿被分片或丢弃,TCP 通过重传恢复,速度直线下降。把两端网卡 MTU 调整后,问题立刻消失。这个案例里,不抓包根本看不出来重传模式跟包大小强相关,只会傻傻认为是线路带宽不够。
4.2 案例二:间歇性延迟尖刺,元凶是 ARP 震荡
某应用频繁出现“偶发延迟”,每次 3 到 5 秒,之后自己恢复。ping 网关一直正常,流量没有断。
在应用的服务器和应用网关两侧同时抓包。平时抓到的都是正常包,没有异常。等了七八分钟,终于抓到了一次尖刺:客户端发出 SYN 后,隔了 800 毫秒才收到 SYN-ACK。抓包文件里,这段时间前后混了一堆 ARP 请求——客户端在反复请求网关的 MAC 地址。
顺着 ARP 泛滥往下追,发现是网关的某个接口做了热备切换,主备切换时虚拟 MAC 地址发生了漂移。客户端 ARP 表还没更新过来,发的 ARP 请求要么没被响应,要么被滞后处理了,连接建立出现了短暂的“黑洞期”。
这种问题,ping 根本发现不了,因为 ping 用的是 ICMP,ICMP 走的是另一套交互逻辑,应用侧 TCP 建连却对这个抖动非常敏感。抓包把 SY N 到 SYN-ACK 间隔和 ARP 请求的时间线放在一起对比,才真正锁定问题。
4.3 案例三:SYN 到了不回包,防火墙规则在捣鬼
某服务升级后,外部客户端连不上新端口。服务端ss -lntp确认端口已监听,客户端 telnet 不通。
服务器端抓包,发现客户端的 SYN 一个不少全部到达。诡异的是,服务器内核对 SYN 没有做任何响应。继续查内核参数net.ipv4.tcp_max_syn_backlog、半连接队列没有溢出,netstat -s也没看到 SYN 被丢弃的计数。
此时抓包窗口正好在防火墙后面:把防火墙规则倒出来看,发现有一条链上顺序里把新端口对应的目标地址写进了 DROP 规则,且这条规则排在了 ACCEPT 之前。IP 层的数据包到达后,得先过防火墙规则检查,被 DROP 了之后,TCP 协议栈压根没有机会看到这个包。
那为什么抓包能抓到 SYN?因为抓包点在防火墙前面。这件事给我的教训就是:先确认抓包点在数据路径的哪一段,不要只看到数据包到了就下结论,要确认它有没有穿过整个协议栈。
5. 常见问题与避坑实录
5.1 抓不到包?先检查这四处
- 网卡抓错了,用
-D列清楚再选。 - 过滤规则写太严了,比如你只抓
port 443但业务实际用的是 8443,就什么都没了。 - 报文被 offload 功能处理了,某些网卡开启 GRO、LRO 之后,小包会被合并成大包,你抓到的可能不是原始形态。
- 抓包权限不足,某些环境中 tcpdump 需要 root 或 CAP_NET_RAW 权限,普通用户可能拿不到包。
容器场景下更要注意:在宿主机上抓包不一定能看到容器内的完整流量,因为容器有自己的网络命名空间。要在容器所在的 netns 里抓包,或者直接在容器内部跑 tcpdump(如果镜像里装了的话)。
5.2 抓出来的包看不懂怎么办
我看过不少人抓包时很兴奋,抓到文件后打开 Wireshark 就傻了:全是乱序、重传、Dup ACK,不知道从哪看起。
我的建议分三步走:
- 先用
capinfos看文件基本信息:抓包时长、平均流量、包个数。 - 再用 Wireshark 的“统计 -> 会话”和“统计 -> IO 图”看宏观趋势。IO 图能直观看到哪个时段流量异常。
- 最后才聚焦到可疑连接上,右键“追踪流 -> TCP 流”,看整个交互过程。
如果是纯命令行环境,可以用 tshark 快速统计重传次数:
tshark -r capture.pcap -q -z io,stat,1 tshark -r capture.pcap -Y "tcp.analysis.retransmission" | wc -l5.3 别忘了在追问题前先看时间戳
tcpdump 默认输出带时间戳,但那个时间戳是相对开机时间还是绝对时间,看你加不加参数。排查延迟问题时,我强烈建议加-tttt,让每条记录显示完整的日期和绝对时间。
分析时还要注意:抓包文件里的时间戳反映的是抓包机器本地时钟,不是网络时间。如果两端联动分析,一定确保系统时间已同步。我曾经在一次排查里把时钟偏差当成链路延迟,折腾了大半天才发现是两台服务器时间差了 30 秒,做分析时牛头不对马嘴。
5.4 别让抓包本身成为“帮凶”
生产环境抓包要谨慎。抓包工具虽然不修改数据,但长时间全量抓大流量,会把 CPU 和内存吃得很高,缓冲区满后丢包率还会上升。抓包期间的性能下降,可能会让原本不那么明显的问题反而放大。
我认为比较稳妥的操作是:先小流量验证抓包可行,再放宽到目标流量;限制文件大小和抓包时长;抓完立即停止并分析,不要一直挂在那里。如果遇到突发大流量,宁可丢弃部分抓包数据,也不要让主机因为抓包而无法服务用户请求。
写在最后的体会
排查网络问题这些年,最大的体会是:定位问题靠逻辑,确证问题靠抓包。tcpdump 不会直接告诉你“网关坏了”或者“防火墙拦了”,但它会诚实地把每一个经过的包展示给你看。你只要掌握从现象出发、从包特征反推、用系统状态交叉验证这条思路,大多数疑难杂症都能找到明确的答案。再补充一个我常用的习惯:抓包文件命名时记下一行备注,说明时间、地点、抓到什么现象,隔几天再翻文件时自己也能看懂当初为什么抓它。这一步看似不起眼,但在复杂问题的复盘阶段能省下大量时间。