Wireshark抓包实战:3分钟定位网络超时
发布日期: 2026/07/25 阅读总量: 0
Wireshark抓包实战:3分钟定位网络超时

一、开门见山:我被线上超时逼到抓包

某天下午3点,运维群里炸了:“线上订单服务响应超时,客户端等待15秒才返回500!”我第一反应查服务器日志:Nginx 200,PHP-FPM处理时间<2秒,MySQL查询平均20ms。后端看起来一切正常。客户端说“我们测了3次都超时,不是我们问题”。

这种时候,只有抓包能说清楚到底哪段网络在吞时间。我选了Wireshark,因为GUI直观,能快速过滤出重传、乱序、零窗口等关键信息。

二、我的抓包方案:两层过滤+三种分析视角

2.1 方案对比:tcpdump vs Wireshark

工具优势劣势我的选择场景
tcpdump轻量、可远程执行、脚本友好分析需要命令行;过滤语法繁琐服务端快速抓包后传回本地分析
Wireshark图形化、协议解析强、统计丰富需要图形界面;大文件会卡本地分析pcap、定位问题

我的标准流程:服务端tcpdump抓5秒(用环形缓冲区以免爆盘)→ scp到本地 → Wireshark打开 → 用显示过滤器快速缩小范围。

2.2 完整抓包命令(版本:tcpdump 4.99.1, Wireshark 4.2.0)

# 服务端(Ubuntu 22.04, eth0网卡):
# 只抓对应端口,避免大量无关流量
# -i eth0 接口
# -s 0 抓完整包(默认65535)
# -C 200 单个文件200MB,-W 5 最多5个文件循环覆盖
# -w /tmp/order.pcap 写入文件
# port 8080 只抓目标端口8080的包
tcpdump -i eth0 -s 0 -C 200 -W 5 -w /tmp/order.pcap port 8080

抓5-10秒就够了(超时问题通常在首轮请求就有体现)。文件传到本地:

# 本地Mac
scp user@server:/tmp/order.pcap ./order.pcap

三、实战三步:用Wireshark过滤出问题包

3.1 先看概况:Statistics → Summary

打开文件后,第一眼看Average packet size和Packet length delta。我那次抓到的包:平均包长只有400字节,但有大量小于100字节的ACK包。再去IO Graphs看吞吐量趋势——发现每1秒左右出现一个缺口(无数据传输)。

3.2 核心过滤:TCP重传、乱序、零窗口

直接套用以下显示过滤器(Display Filter):

# 1. 所有TCP重传(包括快速重传)
tcp.analysis.retransmission
# 2. 所有重复ACK(可能指示乱序或丢包)
tcp.analysis.duplicate_ack
# 3. 零窗口通告(发送方停止发送)
tcp.analysis.zero_window
# 4. 窗口满(接收方暂时不能收)
tcp.analysis.window_full
# 5. 一次完整的HTTP请求+响应(过滤指定IP和端口)
ip.addr==10.0.0.1 and tcp.port==8080 and http

那次我执行 tcp.analysis.retransmission or tcp.analysis.duplicate_ack,直接看到37%的包是重传或DupACK。正常的局域网内重传率应该小于1%。

3.3 深入分析:通过跟踪TCP流查看详情

右键任意HTTP响应包 → Follow → TCP Stream,可以看到完整请求响应文本。我发现的异常:客户端发送请求后,服务端立即返回SYN+ACK,但数据包等了800ms才发出——这是典型的**Nagle算法延迟**?不,仔细看Seq和Ack:服务端在等客户端的ACK确认上一个数据段才发送下一段,说明TCP发送窗口太小。

// 伪代码模拟当时的交互(从Wireshark Time列看出):  
// 0ms: Client -> Server: [PSH, ACK] Seq=1, len=1460  
// 800ms: Server -> Client: [PSH, ACK] Seq=1, len=1460 (延迟8倍!)
// 原因:Server的TCP发送缓存填满,等待窗口更新

四、完整代码实现:自动抓包+分析脚本

我将过程脚本化,以后同类问题一键排查。

4.1 自动部署抓包脚本(bash+expect)

#!/bin/bash
# 用法:./capture.sh   
SERVER=$1
PORT=$2
DUR=$3
ssh root@$SERVER "tcpdump -i eth0 -s 0 -C 100 -W 3 -w /tmp/cap.pcap port $PORT & sleep $DUR; kill %1"
scp root@$SERVER:/tmp/cap.pcap ./$(date +%Y%m%d_%H%M)_$SERVER.pcap
echo "Done: $(ls -lh *.pcap)"

4.2 生成分析报告(Python 3.10 + pyshark 0.6)

pyshark是Wireshark的命令行版tshark的封装,可以程序化分析:

# analyze.py
import pyshark
import sys

cap = pyshark.FileCapture(sys.argv[1], display_filter='tcp.analysis.retransmission')
print(f"File: {sys.argv[1]}")
print(f"Total retransmissions: {len(cap)}")
for i, pkt in enumerate(cap):
    if i >= 5: break
    print(f"  Retransmit {i+1}: {pkt.sniff_time} - {pkt.ip.src}:{pkt.tcp.srcport} -> {pkt.ip.dst}:{pkt.tcp.dstport}")
cap.close()

4.3 压测重现问题(jmeter或wrk)

# wrk压测,模拟高并发
wrk -t4 -c200 -d30s http://10.0.0.1:8080/order
# 同时开另一个终端抓包
tcpdump -i eth0 -s 0 -C 100 -W 3 -w /tmp/highload.pcap port 8080 &
sleep 35; kill %1

五、效果数据:抓包前后耗时对比

场景传统排查方式用Wireshark抓包分析提升
定位慢SQL开启general_log,分析半天过滤MySQL Query或慢查询包,5分钟减少95%时间
定位TCP重传看服务端netstat统计、调用链过滤tcp.analysis.retransmission,3分钟减少90%时间
HTTP超时归属两边日志时间戳对不齐抓包直接看到请求发出时间和响应到达时间精准到毫秒

以本文开头案例为例:

  • 传统方式:检查日志、ping、mtr、调优参数,3小时没解决。
  • 用Wireshark:下载pcap后,输入过滤显示重传包,发现服务端到客户端方向的重传率20%+。进一步发现是客户端window太小(由于客户端TCP内核参数net.core.rmem_default设置过低导致每次只能收几千字节)。
  • 定位时间:10分钟。

六、避坑指南(我踩过的5个坑)

坑1:捕获过滤器 vs 显示过滤器 傻傻分不清

Wireshark有两个过滤器:抓包前设置Capture Filter(基于BPF语法)和抓包后设置Display Filter。我一开始用显示过滤器写 port 80,但抓包时没设捕获过滤器,导致pcap文件巨大(包含所有包),打开卡死。
正确做法:抓包时就限制端口、IP、协议,显示过滤器只做精细筛选。

坑2:抓包网卡没开混杂模式

在云服务器上,弹性网卡默认不抓本机不相关的包。如果你的服务使用VIP或多网卡,务必确认tcpdump或Wireshark设置promiscuous mode。我在阿里云没开,只抓到发给本机MAC的包,结果漏掉本机经VIP出去的流量。解决方案:先检查tcpdump -i eth0 -e看目的MAC是否对。

坑3:大文件打开死机

一次抓了20分钟,pcap达8GB。Wireshark在笔记本上直接崩了。解决方案:使用 editcap 拆分文件,或者用 tshark -r big.pcap -Y "filter" -w small.pcap 预过滤后再打开。

# 先用tshark过滤出需要的流
tshark -r big.pcap -Y "tcp.port==8080" -w small.pcap

坑4:忽略时间戳精度

Wireshark默认显示微秒级时间戳,但如果你跨机器分析,需要保证各机器时间同步(NTP偏差<1ms)。我遇到过一次:两台服务器时间差2秒,导致抓包中的请求-响应时间计算完全错误。解决办法:抓包前确认NTP同步,或在抓包文件中手动调整时间偏移(Statistics→Time Shift)。

坑5:HTTPS流量抓了白抓

抓HTTP请求没问题,但HTTPS需要额外步骤。我一开始抓了全是TLS密文。正确姿势:要么在代理层解密(如mitmproxy、Burp),要么导出SSLKEYLOGFILE并加载到Wireshark。具体步骤:

# 服务端应用启动前导出SSLKEYLOGFILE
export SSLKEYLOGFILE=/tmp/sslkey.log
# 重启应用(如nginx)然后抓包
tcpdump -i eth0 -s 0 -C 100 -W 3 -w /tmp/https.pcap port 443
# 本地Wireshark打开pcap后,设置Preference→Protocols→TLS→(Pre)-Master-Secret log filename

七、总结

Wireshark不是屠龙刀,但遇到网络延迟、丢包、超时问题,它就是最趁手的一把手术刀。牢记三步:服务端轻量抓包 → 本地Wireshark打开 → 显示过滤器精确打击。把上面脚本放入你的工具箱,下次线上超时,直接上抓包,别再盲目调日志了。

附:Wireshark常用过滤速查表(我贴桌边)

需求显示过滤器
所有TCP重传tcp.analysis.retransmission
所有快速重传tcp.analysis.fast_retransmission
零窗口tcp.analysis.zero_window
HTTP 500错误http.response.code == 500
DNS查询超时dns.flags.response == 0 and dns.elapsed > 0.1