搞技术的都懂这种场景:业务群里有人喊“网络好慢”,你打开Wireshark,抓了一个几百MB的包,密密麻麻全是报文,一时间不知道从哪看起。这个系列前面聊过抓包环境、基础过滤、常见协议分析,这第四篇我想直接聊一个更贴近实战的问题——拿到一堆包之后,怎么把“慢”“丢”“断”这些现象翻译成证据,再顺着证据链找到根因。
这篇文章适合两类人:一类是刚接触Wireshark 2.x、能抓包但不太会深入分析的网络工程师;另一类是后端、运维、测试同学,经常需要从网络侧验证“到底是应用慢还是链路慢”。我会按实际分析流程来写,从大文件瘦身、TCP性能判断、应用层解码,到tshark脚本化处理,最后用三个我参与过的案例复盘完整的定位过程。每个操作背后我都会解释为什么这么做,方便你换个场景也能套用。
1. 先别急着翻报文,海量pcap要从“统计视角”切进去
很多新手拿到一个几百MB的pcap,习惯性从第一帧开始往下滚动,滚动十几分钟就晕了。这是最浪费时间的方式。抓包文件是一个“证据集合”,你要做的是先看统计信息,建立整体认知,再缩小范围。
1.1 大文件先瘦身:Capture File Properties就是你的体检报告
打开一个大型pcap,我建议第一件事是看Statistics -> Capture File Properties。这里能看到文件里总共有多少包、抓包持续了多长时间、首包和末包的时间戳、平均包速率。这个信息非常重要,因为它直接告诉你“这个文件覆盖的时间窗口是多久”。
举个例子,有一次某人给我一个800MB的pcap,说“你帮我看下这个文件,感觉网络有问题”。我打开File Properties一看,抓包时长只有40秒,平均包速率接近3万pps。这个信息一出来,我立刻意识到:如果业务是偶发卡顿,这个40秒窗口不一定够用;如果是要分析拥塞,那么这个速率下大概率中间链路有问题。有了这个整体认知,我才决定下一步用哪种策略去过滤。
对于超大文件,我还有一个习惯:先用capinfos工具(Wireshark安装目录自带)快速看文件基本信息,不打开图形界面。它输出更清爽,适合写脚本批量检查。比如:
capinfos big-capture.pcapng你能拿到捕获时间、文件封装格式、数据链路类型、包长统计等等。我一般在服务器上用这条命令做“第一眼判断”,确认文件没有抓坏、时间窗口合理,再决定要不要拉到本地用图形界面细看。
1.2 会话与端点视角:先搞清楚谁在和谁说话
大文件瘦身最快的方法不是靠猜,而是看Statistics -> Conversations和Statistics -> Endpoints。这两个窗口是Wireshark里被低估的大杀器。
Conversations会按地址对列出所有通信双方的会话,包括IPv4、TCP、UDP、HTTP等不同层级的视图。每一行会显示收发包数量、收字节和发字节。我一般先按字节数排序,最大的几个会话就是你需要重点关注的对象。比如有一次排查出口带宽被占满的问题,打开Conversations按字节排序,第一名是一个内网IP和某个云存储服务之间的UDP流量,占了总流量的70%以上。顺着这个会话点右键,选择Conversation Filter -> UDP,整个显示区域就只留下这个会话的包,瞬间缩小了分析范围。
Endpoints则能告诉你每个IP、MAC地址整体贡献了多少流量。这个视角适合找“流量大户”或“异常广播源”。比如某个IP发了大量组播或广播包导致局域网内其他机器CPU升高,你通过Endpoints按发送包数排序,基本一眼就能定位。
这里有个操作心得:看到可疑会话后,不要只做视觉上的滚动,直接用右键Conversation Filter把过滤条件应用到显示过滤器,这样后续所有分析都在这个小数据集上进行,界面响应速度会快很多。大pcap上如果直接拖来拖去,每一步操作都可能卡几秒钟,非常影响思路。
2. TCP性能分析:拿“图”说话,比拿数字说话直观得多
抓包分析里最常碰到的需求是“某个应用慢”。应用慢可能是服务端处理慢、客户端处理慢、网络丢包重传、链路带宽拥塞、TCP窗口太小等等。Wireshark图形化工具能帮你快速把这几种原因区分开。
2.1 Time Sequence Graph:一眼看出重传、窗口和乱序
TCP时序图(Stevens图)是分析TCP传输效率的核心工具。在新版本里菜单位置是Statistics -> TCP Stream Graphs -> Time Sequence (Stevens),老版本则在Telephony -> TCP Stream Graphs下。使用时必须先选中一个TCP流,或者先右键某个TCP包选择Follow -> TCP Stream,再打开这个图。
这个图的X轴是时间,Y轴是序列号。正常情况下,如果发送方以恒定速率发送数据,图中的曲线应该是一条稳定上升的斜线。如果曲线出现“回退”,说明发生了重传——因为序列号倒退表示之前发的包又发了一遍。如果曲线出现“平台期”,也就是一段时间内序列号不增长,说明发送被阻塞了,极大概率是TCP窗口耗尽,或者对端没有及时确认。
一次实际的排查案例:某服务反馈文件上传偶尔要等好几秒。我抓包后打开Time Sequence Graph,发现曲线是锯齿状——涨一段、停一停、又涨一段,而且每次下降幅度很小。这说明发送方一直在重传数据,结合TCP层tcp.analysis.flags里的乱序标记,判断是中间链路把包的顺序搞乱了,导致接收方发出大量Duplicate ACK,发送方被迫重传。后来在交换机侧调整了队列策略,问题解决。如果只盯着单个报文看,很难总结出这个规律,但图上一眼就明白了。
2.2 IO Graph:多画几条线,把“症状”可视化
IO Graph适用于看整个抓包时间范围内的流量趋势。默认的IO Graph只显示总的包/字节数,但它的强大之处在于你可以添加多个过滤器,画多条折线对比。在Statistics -> IO Graph里,点左下角的“+”,添加一条tcp.analysis.retransmission,再添加一条tcp.analysis.zero_window,然后选不同的颜色和风格。
为什么要看这几条线?我习惯把IO Graph当成“心电图”来看:吞吐量(所有包)是主旋律,重传是“心律不齐”,零窗口是“心肌缺血”。如果重传线的尖峰和吞吐量下降的时段对齐,说明丢包重传拖垮了传输效率;如果零窗口频繁出现,说明接收方应用层处理不过来,导致缓冲耗尽,这在排查“应用慢”时是强有力的证据。
还有一次,某数据库主备同步延迟。我在IO Graph里同时画了同步流量和重传包,发现重传尖峰大约每5秒出现一次,和同步流量高峰完全错开。通过进一步抓包确认,同步流量的高峰正好撞上了另一个备份任务的带宽占用,中间链路拥塞导致丢包。这个排查如果没有IO Graph的对比视图,靠人工看报文得花好几倍时间。
2.3 TCP三层分析法:从Expert Info到重传细节
我很建议新手形成一套固定的TCP排查流程,不要每次抓到包都从头到尾翻。我自己常用的顺序是这样的:
第一步,先看Analyze -> Expert Info。Wireshark的专家系统会把各种异常自动分类成错误、警告、备注。虽然它有时候会误报(比如服务端主动关闭连接被标成TCP RST错误),但它能给你一个“异常密度”的整体印象。如果Errors和Warnings非常多,说明这段抓包里确实有大量网络异常,值得往下挖。
第二步,判断重传的性质。显示过滤器输入tcp.analysis.retransmission可以列出所有重传包。看它们的[TCP Retransmission]说明里有没有额外标注,比如[TCP Fast Retransmission]就是快速重传,通常由乱序触发;而[TCP Retransmission]没有前缀说明的更可能是超时重传。快速重传意味着链路存在乱序或者丢包但接收方能感知,超时重传则往往发生在链路长时间无响应、双向都有问题时。这个区分直接决定了你去查中间链路还是查对端性能。
第三步,看接收窗口。过滤器tcp.window_size_value可以查看每个包的窗口值。如果某个连接的有效窗口长期接近0,说明对端应用层消费能力差,瓶颈在服务器进程而不是网络。如果窗口正常但实际吞吐很低,那就是发送方或者链路的问题。
这套三层分析法几乎适用于所有TCP慢速类问题,你可以记下来反复用。
3. 应用层解码:HTTP/2和TLS不透明,但总有办法看透
现在很多业务流量都是HTTPS,再往前一步,HTTP/2又让多路复用成为常态。如果只停留在TCP层分析,很多应用层问题根本看不到。这一节重点讲怎么把“加密黑盒”打开一个口子。
3.1 HTTP/2的多路复用:一个TCP流里多个请求,要拆帧看
HTTP/2在同一个TCP连接上并行传输多个请求/响应,一个TCP流里混着不同stream的数据帧。Wireshark会自动识别HTTP/2并解析HEADERS、DATA、SETTINGS、WINDOW_UPDATE等帧类型,但如果没有合适的过滤条件,看起来会比较乱。
分析HTTP/2服务性能时,我习惯先过滤出某个TCP流,再按http2.streamid分组看每个stream的帧。比如想定位“为什么某个页面图片加载慢”,可以这样过滤:
tcp.stream eq 0 && http2.streamid eq 5这会筛选出TCP流0里的stream 5,也就是特定请求的完整帧序列。结合时间列,你可以看出从客户端发HEADERS帧到服务端返回HEADERS帧之间隔了多久。这个间隔就是服务端处理时间。如果多个stream的HEADERS帧返回时间都比较长,可以判断服务端并发处理能力不足或上游响应慢,而不是链路问题。
另外一个实用技巧:右键一个HTTP/2请求帧,选择Follow -> HTTP Stream,Wireshark会把该stream的请求和响应内容拼起来给你看,类似于HTTP/1.1的分析体验。注意,这个功能依赖解密后的数据,如果你抓的是明文HTTP/2(内网常见)就直接可用;如果是TLS加密,需要配合3.2小节的解密配置。
3.2 TLS解密:SSLKEYLOGFILE是怎么用的
不是说抓了HTTPS就只能放弃应用层分析。Wireshark支持通过TLS会话密钥日志(SSLKEYLOGFILE)来解密抓包数据。前提是你能访问到客户端环境,因为现代浏览器和大部分HTTP库都支持通过环境变量导出会话密钥。
具体怎么操作:在客户端机器上,启动浏览器或curl前设置环境变量:
export SSLKEYLOGFILE=/tmp/tls-keys.log然后在Wireshark的Edit -> Preferences -> Protocols -> TLS(老版本叫SSL),在(Pre)-Master-Secret log filename里填上这个文件路径。之后重开抓包并触发HTTPS请求,Wireshark就能自动解密显示HTTP/2或HTTP明文。Firefox和Chrome都遵循这个机制,curl在Linux/macOS下也支持,Windows下的curl需要确认版本。
这里必须泼一盆冷水:这个方法只能用于你自己有权限的测试环境和设备。拿到密钥日志后,Follow -> HTTP Stream就能看到完整的请求头、请求体、响应内容,包括cookie等敏感信息。所以千万别在未经授权的环境里乱抓,也不要抓完把pcap文件到处分发。实际做性能分析时,我通常会在测试环境里复现问题,开启SSLKEYLOGFILE,然后通过解密后的数据看服务端响应时间、资源加载顺序、缓存命中情况,非常有用。
3.3 把“一次HTTP请求”拆成可量化的时间片段
当业务报“网页慢”,我拿到解密后的HTTP流量后,会用Statistics -> HTTP -> Request Sequences来看页面所有资源的请求时间线。这个视图能展示每个URL的开始时间、结束时间、响应码,一眼能看出哪些资源是串行加载的,哪些并行加载被卡住了。
更细的指标是看HTTP的时间字段。Wireshark对HTTP请求/响应会计算一些特殊字段:
http.time:请求发出到收到响应的时间间隔,是客户端视角的完整RTT加服务端处理时间。http.response_in:服务器返回响应前经过的时间。http.t(也叫http.time的同类字段,不同版本名称有差异)需要配合过滤来用。
举个例子,过滤器http.time > 1可以筛选出所有响应时间超过1秒的请求。把这些慢请求按时间排序,再结合3.2的解密数据看请求体大小和资源类型,基本就能判断是某个后端接口本身慢,还是前端在大并发拉取资源导致连接排队。这个分析思路比单纯用浏览器开发者工具看到的瀑布图更底层,因为它包含了真实网络传输时间,而不是本地渲染时间。
4. 高级过滤器与命令行工具:靠鼠标点不出来的效率
Wireshark的图形界面交互很好,但真要处理大量数据或者做重复性巡检,命令行工具和高级过滤表达式才是效率倍增器。这一节讲的都是我从实际工作中沉淀下来的。
4.1 十个我常用的高价值显示过滤器
过滤器是Wireshark最核心的武功,但很多人只会用ip.addr == x.x.x.x这类基础过滤。我整理了一下近几年用得最多的高级过滤条件,每个都配一个典型场景:
| 过滤表达式 | 用途说明 |
|---|---|
tcp.analysis.flags && !tcp.analysis.flags.rst | 只看TCP层分析标记的异常包,但排除RST,适合快速浏览非正常断开流量 |
tcp.analysis.retransmission | 列出所有重传包,慢速问题第一步必看 |
tcp.analysis.fast_retransmission | 只看快速重传包,用于判断乱序触发场景 |
tcp.analysis.zero_window | 只看零窗口通知,判断接收方处理瓶颈 |
http2.headers.content-type | 过滤HTTP/2响应头中content-type为指定类型的帧,例如筛选JSON请求 |
dns.flags.response == 0 && dns.qry.name contains "sso" | 只看DNS查询请求,快速查域名解析结果 |
ssl.handshake.type == 1(新版tls) | 只看TLS ClientHello,统计有哪些客户端发起握手 |
| `icmp.type == 8 | |
frame.time_delta_displayed > 1 | 查看帧间隔大于1秒的节点,用于找“静默期” |
tcp.window_size_value < 65536 | 快速定位窗口值偏低的TCP包,初步判断接收能力 |
这些过滤表达式有一个共同特点:它们都是协议解析后的字段,Wireshark已经帮你把原始字节翻译成了语义信息。用它们可以快速从几十万包里提取出有价值的异常集合。我通常会把多个条件用&&组合,比如:
tcp.analysis.flags && !tcp.analysis.flags.rst && ip.addr == 10.0.0.8这条能过滤出与目标主机相关的全部TCP异常事件,非常节省时间。
4.2 tshark脚本化处理:不做“鼠标工程师”
如果每天要分析多份pcap,或者要从长期运行的抓包中提取统计指标,用tshark批量处理是正解。tshark是Wireshark的命令行版本,支持大部分显示过滤器语法,还能通过-T fields直接输出你想要的字段。
一个典型的场景:提取某个pcap里所有HTTP请求的URL和状态码。命令是这样的:
tshark -r capture.pcapng -Y "http.request" -T fields -e http.host -e http.request.uri -e http.response.code输出是每行一条记录,可以用awk/sort等命令继续做统计。比如统计某个API的请求量分布:
tshark -r capture.pcapng -Y "http.request && http.host contains api.example.internal" -T fields -e http.request.uri | sort | uniq -c | sort -nr这个能力在“复盘线上事故”时特别有用。有一次业务方问“昨晚是不是有人调了批量接口导致数据库压力大”,我拿到前一晚的pcap,用tshark把对应路径的请求频次按分钟聚合,输出时间序列折线图数据,直接定位到某台服务器在凌晨2点到3点间发起了上千次批量查询。整个过程不到5分钟。
另外几个命令行工具也值得配套使用:
editcap:从大文件里截取指定时间段范围或指定数量的包,生成小pcap,方便分享给同事。mergecap:合并多个抓包文件,适合多端口同时抓包后统一分析。reordercap:按时间戳重新排序pcap,有些网卡抓出来的包时间戳是乱序的,排序后Wireshark分析结果才准确。
在远程服务器上分析时,我一般不会用图形界面,用tshark跑一条命令拿统计结果,再决定是否下载相关片段到本地细看。这样做节省带宽和内存,也更低调。
4.3 抓包过滤器与显示过滤器别搞混
这是一个老生常谈但依然有人常犯的错误:抓包过滤器(Capture Filter)用的是BPF语法,在抓包那一刻就决定“哪些包进内存”;显示过滤器(Display Filter)用的是Wireshark表达式,抓到的包一个不少,只是显示时隐藏。
典型BPF写法:
host 10.0.0.8 and tcp port 443这条会过滤源或目的IP是10.0.0.8且TCP端口是443的包。它的执行效率远高于显示过滤,因为它在底层直接丢包。适合在流量很大、担心抓包文件过大时使用。但代价是:如果抓包过滤条件设得太严,你后面就再也看不到被丢弃的包了。
我的建议是:正式排查时,能用显示过滤解决问题就别用抓包过滤限制太死。存储便宜,时间成本贵。万一你过滤掉了关键上下文,比如漏掉了握手包或者重传包,后面怎么分析都补不回来。只有在明确知道“我只关心某IP的443流量”并且流量巨大、磁盘可能写满时,我才用BPF抓包过滤。
5. 实战复盘:三个让我印象深刻的定位过程
光讲工具不讲案例,等于给了一把好刀但不知道怎么用。下面三个案例都发生在我经历过的真实环境里(具体信息做了脱敏处理),我尽量还原当时的分析路径和判断逻辑,你可以把它当思维演练。
5.1 案例一:重传不多,但应用就是卡
现象:某个内部系统的页面经常卡顿,业务方坚持说“网络有问题”。但我看抓包文件里TCP重传率不到1%,数值上很健康。这非常容易造成误判——不是所有网络问题都由重传体现。
详细分析过程:我打开TCP流,先看Time Sequence Graph,发现曲线不是平滑上升,而是每隔几百毫秒出现一个极短的水平台阶。这个形态和“拥塞导致丢包重传”是不同的,重传导致的曲线会下降或回退,而水平台阶只说明发送动作暂停了。
接着我看接收方的TCP窗口字段,发现有一个时间点之后,接收方通告窗口不断减小,最终出现tcp.analysis.zero_window。这些零窗口包和页面的白屏时间段精确对齐。真相是:某个网关软件在接收数据时没有及时把数据交给上层应用,导致TCP接收缓冲区被填满,Zero Window告诉发送方“我吃不下了”,发送方只能等待。问题不在链路,而在端到端的接收处理逻辑。后来升级了网关组件版本后卡顿消失。
这个案例给了一个很重要的教训:看到“重传率不高”别急着下结论说网络没问题,多画几条TCP图,看看曲线形态和窗口变化,往往能找到真正的瓶颈。
5.2 案例二:客户端频繁连不上服务器
现象:某个移动端App用户反馈隔一段时间就“服务器连接失败”,重启App又恢复正常。
抓包后发现一个典型模式:客户端发SYN包,服务端没回SYN-ACK,客户端隔1秒、3秒、7秒重试SYN,最后放弃并报了ConnectTimeout。从流量看,SYN没丢,因为抓包点在服务端入口能看到SYN到达;但服务端没有后续回应。这说明问题几乎可以排除链路丢包,重点怀疑服务端的连接接收能力。
顺着这个思路看Linux服务器状态,确认监听队列(accept queue)在现象发生的时刻溢出过。为什么溢出?因为服务端进程处理连接请求的速度跟不上新连接的到达速率,通常是业务线程池满或者存在阻塞操作。后来开发侧优化了连接处理逻辑,把半连接队列和全连接队列的内核参数也调大了,故障消失。
这里要说一个抓包选点的经验:如果只在客户端抓包,你只能看到“SYN发了没响应”,无法判断包是否真的到达服务端。所以我在服务端接入交换机同时抓了一份包做对照,两份对比后快速锁定了问题边界。排查网络问题时,采样点选在哪个位置,比用什么工具重要得多。
5.3 案例三:夜间带宽被神秘流量打满
现象:某分支机构的专线带宽每天凌晨两点被占满,业务方想知道到底是什么流量。
打开凌晨时段抓包文件,先用Statistics -> Endpoints按字节数排序。第一名是一个内网ERP服务器和某个公网存储服务的大量UDP流量。点了Conversation Filter之后,发现这些UDP包长度非常规律,大半都是约1400字节的大包,且目标端口很集中。翻看几个包的应用层协议解析,确认是某种云备份客户端的增量同步流量。
再往前查,这个备份任务为什么凌晨两点启动?从DNS请求时间线看到,定时任务通过内网DNS解析一个备份域名,触发了客户端启动全量备份。之前没限速,所以把专线带宽吸干。解决办法很简单:在备份客户端配置里限速,并把备份时间错开。如果不用Endpoints和Conversation Filter,这么多UDP流量手动翻包根本看不出规律。
这个案例没什么高深技术,但值得提的是“先整体统计、再缩小范围”这个朴素思路。很多复杂问题最后查出来都是简单的配置问题,难的是在茫茫包海里找到那只“老鼠”。
6. 实践之后的一些关键经验
每次做完网络分析,我都会把经验和教训沉淀下来。挑几个对新手最有价值的说说。
第一个经验:抓包前先确定采样点位置和方向。同一个现象,在客户端抓、在服务端抓、在中间交换机镜像端口抓,看到的证据可能完全不一样。抓包点选在哪里,取决于你想证明什么。比如想证明链路丢包,最好在两端同时抓,用frame.time_delta_displayed比较同一段TCP流的时间偏移;想证明服务端不处理,就在服务端入口抓。
第二个经验:抓包时长和文件大小要适度。盲目抓大文件只会拖慢分析效率。我一般先根据现象猜测可能的方向,抓几分钟到几十分钟,然后用File Properties确认覆盖了问题发生的时间窗口。如果窗口没覆盖到,再重新抓,别在已经抓到的大文件上死磕。
第三个经验:异常信息一定要看Expert Info,但也不能全信。Expert Info的标记是基于启发式规则的,有时候正常行为会被误标成错误,比如SYN重传、RST主动断开。我会把它当成“体检报告的异常指标提示”,真正确认问题还要结合具体报文和时间线。
第四个经验:保存自己的工作集。Wireshark允许你把显示过滤器、着色规则导出配置文件,换个环境立马导入继续用。我一般会把常用过滤器按场景分组命名,比如“TCP重传分析”“HTTP慢请求”“DNS查询回溯”,这样每次打开新pcap不用重复输入长表达式。
还有一个小技巧:分析完任何一个案例,我都习惯在pcap里找一个“正常流”和“异常流”做对比。正常流作为基线,异常流作为变量,两者对比之后,根因往往非常清晰。这个思路不仅适用于Wireshark,也适用于任何性能问题排查。
这一篇没有刻意设计一个“网络分析全套流程”,因为真实世界的排查路径本来就是蜿蜒的。但如果你能熟练掌握统计视图缩小范围、TCP图形工具判断瓶颈、应用层解查看透内容、tshark脚本提升效率这四板斧,大部分网络疑难杂症在你手上都会变成有迹可循的证据链。下次再有人说“网络慢”,你至少可以从容地打开抓包文件,先看一分钟统计信息,再说一句:“我大概知道问题在哪了,等我抓个包验证一下。”