Wireshark抓包实战:从TCP重传到MTU问题定位
如果要我在自己电脑上选一个必须常驻的排障工具Wireshark一定排前三。别急着说它是网络工程师专用这些年我用它排查过接口超时、数据库连接被重置、视频播放卡顿甚至还有同事抱怨“邮箱发不出去”这类看起来完全不相干的问题。很多人一听抓包就头大觉得要面对一堆十六进制字节流其实Wireshark的协议解析已经把绝大多数信息翻译成了人能看懂的语言你只需要掌握几个关键动作选对网卡、写对过滤器、知道TCP的几次握手和重传意味着什么。这篇文章就用一个尽量接近真实工作场景的排查过程完整演示一次Wireshark抓包分析该怎么做。适合刚入门的新手也适合那些用过几次但一直没形成套路的人至少能少走一点我当初走过的弯路。1. 为什么我会把Wireshark当成排障工具箱里的第一选择1.1 从一次“日志一切正常”的故障说起某内部系统曾经反馈一个数据查询接口每隔几分钟就会超时一次每次只持续几秒钟之后又自动恢复。第一反应是查应用日志结果很有意思服务端日志显示请求正常收到、响应也正常返回但调用方日志却记着“read timeout”。两个日志摆在一起结论是矛盾的。继续ping对端地址延迟很低丢包率是零。这时候排查方向开始发散有人怀疑数据库连接池有人怀疑负载均衡配置重启了好几次服务都没用。最后用Wireshark在客户端机器上抓了十分钟包真相非常直白。日志里的超时根本不是服务端处理慢而是客户端连接池里有一条长期空闲的TCP连接被中间设备静默回收了。下一次请求恰好复用了这条连接请求刚发出去立刻收到一个RST包应用层就把这次失败记成了“read timeout”。这种问题只靠看日志完全看不出来因为日志只记录应用层的发生了什么不会记录TCP层到底发生了什么。网络是整个系统里最典型的“黑盒”而Wireshark就是把这个黑盒打开的那根探针。1.2 它到底能做什么又做不了什么我经常跟同事说Wireshark不是万能的但它能帮你省掉大量“用猜的”时间。它能做的事包括实时捕获网卡上的数据包并按协议解析用显示过滤器快速筛出目标流量统计TCP重传、往返时延、HTTP请求耗时定位连接重置、丢包、延迟抖动导出为pngcap文件后用命令行工具批量分析。这些能力合在一起足够覆盖日常工作中80%以上的网络层、传输层问题。做不了的事也得说清楚。它不能替代应用日志去判断业务逻辑也看不到物理链路内部的问题比如光模块光衰这种情况你在Wireshark里只能看到链路层误码率激增或者表现为TCP层大量重传。它也不会自动告诉你“这是谁的锅”它只负责把数据包一层层拆开给你看证据。很多人觉得Wireshark难用是因为期待它直接给出结论实际上它是一个证据生成器结论还得靠人从证据链里推出来。2. 抓包前的三个动作决定你后面能不能少走弯路2.1 选对网卡顺便把混杂模式讲明白打开Wireshark首页第一步是选捕获接口。这一步很多人会随手点一个然后发现什么都抓不到。真实网卡、虚拟网卡、回环接口经常混在一个列表里选错网卡是新手最常见的第一个坑。在物理机上排查时优先看接口列表里的“发送速率”和实时流量预览流量有明显跳动的那一块通常就是正在工作的网卡。接下来是混杂模式。默认情况下网卡只把发给自己的数据报交给系统处理混杂模式的意思是让网卡把介质上能收到的数据包都收下来。但这里有个很关键的B小常识在普通交换机上做端口镜像之前即使开启了混杂模式你也只能看到发给自己的包、自己发出去的包和广播包因为交换机会按MAC地址把帧精确转发到对应端口根本不会送到你的网卡上。只有把抓包机接到交换机的镜像口或者用分光器、集线器这类设备时混杂模式才能真正看到“别人的流量”。所以排查东西向流量时别一门心思开混杂模式先把接入位置想清楚。2.2 权限、回环接口和远程抓包权限问题是刚入门时最容易把人卡住的坎。Linux下不加上足够的权限Wireshark连抓包接口都打不开Windows下很多环境需要以管理员身份运行。操作系统限制直接访问原始套接字这是安全机制不是软件故意刁难。如果你用的是Linux桌面还可以给当前用户配置抓包权限组省得每次都敲sudo。还有一个非常容易漏掉的接口loopback回环接口。本机进程之间的通信比如后端服务连本机的数据库走的是虚拟回环路径普通物理网卡完全看不到这些包。Wireshark的接口列表里一般会单独列出一个lo0或者Loopback Adapter抓这种本机到本机的流量必须选它。另外远程抓包可以配合命令行工具在远端采集再把文件拿回本地分析。但决定远程抓包前务必确认已经获得机器所有者和网络管理方的授权只在自有或明确受权的环境里做这件事别拿抓包工具去做任何越界的事。2.3 保存规则别等D盘塞满才想起来很多人抓包时让Wireshark一直跑抓到几百兆甚至几个G才停后面打开文件都卡成幻灯片。Wireshark默认会先把包存在内存缓冲区里停止后才能真正落盘如果你需要持续采集最好在开始之前就设置好保存规则。在捕获选项里可以配置“多文件”模式按大小或时间自动切换文件比如每个文件50MB保留最近20个还可以设置自动停止条件。我自己更常用的是命令行采集工具方便定时任务化dumpcap -i eth0 -f tcp port 8080 -b filesize:51200 -b files:20 -w /tmp/capture.pcapng这段命令的意思是每50MB切换一个新文件最多保留20个文件写满后自动淘汰最老的。对排查“偶发问题”特别有用因为你不知道故障什么时候出现需要提前大量囤积流量但又不能把磁盘囤爆。抓包文件大小也可以粗估普通业务请求一个包也就1KB到2KB每秒几十个请求的时候一小时也就几百MB按这个量级配置一般不会出问题。3. 从一次HTTP请求看懂TCP连接的一生3.1 三次握手的数据包特征模拟一个最简单的实验本机用curl请求某个端口服务然后在Wireshark里把过滤器写成tcp.port 8080。开始抓包后执行一次curl停止后你会看到一系列TCP包前三个包就是教科书里反复讲的三次握手第1个包客户端到服务端标记SYN表示“我想建立连接我的初始序列号是xxx”。第2个包服务端到客户端标记SYNACK表示“收到你的请求我的序列号是yyy确认你的序列号”。第3个包客户端到服务端只标记ACK表示“连接建立成功”。在Wireshark的报文列表里Flags列会直接显示这些标记的缩写。点开TCP层的详情还能看到Sequence Number、Acknowledgment Number、Window Size等字段。如果这个阶段只看到SYN反复重发对端始终不回SYNACK一般是对端服务没监听或者防火墙把包丢了。如果看到SYNACK但客户端一直不回ACK就要怀疑连接队列溢出或者客户端侧丢弃了回应。这种判断在排查端口不通时非常管用。3.2 时间列和时延的读法抓包列表默认的时间列是“相对第一个包的时间”排查性能问题时我更常用“Time since previous displayed packet”。在列头右键可以添加这一列它会显示当前包和上一个显示出来的包之间的时间差。这个差值用来观察请求和响应之间的间隔非常直观。HTTP请求发出后到收到响应首字节的时间通常被叫作首字节时间。如果所有请求的Delta时间都很小只有偶尔几个请求特别大往往就对应连接被回收、DNS解析变慢或者网络瞬时抖动如果每个请求的Delta都很大那重点应该转向服务端处理能力。Wireshark的Statistics菜单里也有HTTP请求统计可以直接看到每个请求的耗时分布。更简单的方式是右键任意HTTP请求选择Follow HTTP Stream它会把这个TCP流里所有请求和响应正文拼成一个完整的会话视图应用层交互一目了然。3.3 挥手、重传和连接重置连接关闭同样值得看。正常四次挥手的特征是FIN、ACK交错出现最后连接资源被回收。如果看到RST说明连接被异常终止常见原因包括进程崩溃、端口未监听、安全设备注入干扰。应用日志里报“Connection reset by peer”时只要看RST包的来源IP地址就能知道是服务端主动重置还是中间设备注入的RST这一步排查方向差别很大。TCP重传在Wireshark里会用醒目的标记提示“TCP Retransmission”。看到重传不一定等于丢包也可能是网络延迟抖动导致包乱序接收方触发了快速重传。所以遇到重传时要同时看“Out-of-Order”“Previous segment lost”这些分析标记结合起来判断。后面我会专门写一下这种误判问题。4. 显示过滤器是Wireshark的魂先理解套路再背语法4.1 显示过滤器与捕获过滤器一个对比就懂了Wireshark里其实有两种过滤器建议先区分清楚。捕获过滤器作用在采集阶段用的是BPF语法目的是从源头减少抓包量显示过滤器作用在已经抓到的数据包集合上目的是分析语法更像一门口语化的查询语言。日常90%的精力都应该放在显示过滤器上因为抓包阶段过滤太狠很可能会把关键线索也滤掉。显示过滤器的核心逻辑非常简单字段操作符值。协议树里能看到的所有字段都能当条件比如ip.addr、tcp.port、dns.qry.name。操作符包括等于、不等于、大于、小于、包含等逻辑组合用and/or/not。举个例子ip.addr 192.168.50.10 tcp.port 8080这条的意思是把源或目标地址为192.168.50.10、端口为8080的包全部显示出来。还有一类字段很特殊比如tcp.analysis.retransmission它不是包上的真实字段而是Wireshark分析引擎根据包内容计算出来的标记字段。这类带analysis关键字的字段是定位问题的神器。4.2 常用场景的高频过滤器我平时最喜欢用的那么几条列出来可以直接套只看某个IP与某个端口ip.addr 192.168.50.10 tcp.port 443只看HTTP POST请求http.request.method POST只看DNS查询里含某个域名的包dns.qry.name contains example.com只看建立连接的SYN包tcp.flags.syn 1 tcp.flags.ack 0这里必须提醒一个最容易出错的点ip.addr是“源或目标任意一个满足”的集合字段。如果你写ip.addr 192.168.50.10 ip.addr ! 192.168.50.20看起来像“源或目标是50.10同时不是50.20”但因为一个包里有src和dst两个字段完全可能出现src50.10、dst50.20的情况结果被错误排除。更严谨的写法是分别写ip.src和ip.dst。这个坑我踩过不止一次现在凡是涉及“一方到另一方”的条件我都会拆开字段写。4.3 着色规则和IO图表的组合用法过滤器能把异常包筛出来但海量流量里最直观的还是可视化。着色规则可以自定义比如把TCP重传标成红底、把HTTP 5xx响应标成橙色、把自己关心的业务IP标成绿色。着色规则只是显示层的变化不改变任何数据但能成倍提高肉眼的扫描效率。排查突发流量时我最喜欢用Statistics - IO Graph把横轴设为时间纵轴统计每秒包数或字节数然后叠加一个字段值比如tcp.analysis.retransmission。如果业务反馈“下午3点突然卡了一下”IO图上的重传尖峰就能和故障时间精确对上不用一包包往前翻。掌握这套组合拳基本就甩开只会双击开包的选手一大截了。5. 一次间歇性接口超时的完整排查记录5.1 故障现象和最初两条线索某内部系统的服务A调用服务B每天随机出现几十次超时每次持续几秒就自行恢复。A的日志写着“connection reset”B的日志却写着“no request received”。这两条日志加起来给人的感觉是请求根本没到B。从应用层开始排查ping服务B的VIP地址一切正常telnet对应的端口偶尔失败。由于问题不规律我们决定先在服务A上持续抓包过滤器先收窄到对端IP和端口写成host B_IP tcp.port 8080这条BPF捕获过滤器然后让它后台跑起来。5.2 从包里逐层排除最终定位到网卡MTU抓到足够的包之后我的排查顺序是这样的先打开Analyze - Expert Info直接看Wireshark自动标记出来的异常记录。列表里有一批红色级别较高的TCP RST记录都在故障时间窗内。第一步看RST包的来源IP。结果发现这些RST大部分来自中间负载均衡设备的地址而不是服务B的地址。也就是说连接不是被B的应用层踢掉的而是中间设备重置的。第二步顺着RST所在TCP流往回看。在这些异常连接里大量出现“TCP Previous segment lost”和“TCP Out-of-Order”的分析标记说明链路层有丢包现象而不仅仅是连接被重置。第三步统计一下重传包的大小。发现重传的包几乎都是接近1500字节的大包小包完全没有重传记录。这个规律很关键它把问题指向了MTU不一致。第四步对比相关设备的MTU。服务A网卡MTU是1500服务B是1400而中间负载均衡设备的MTU设置成了1480。当服务A发送超过1480字节的大包时中间设备获得大包后无法正常处理又不返回ICMP不可达消息发送端完全不知道要降低MSS于是只能不断重传最终触发RST。整个链条通过SYN包里的MSS选项和IP层的DF位都能在包里找到证据。5.3 修复验证与复盘心得后续调整方式很简单把链路MTU统一并让路由侧对入向流量做MSS钳制让大包在进入链路之前就被拆分到安全尺寸。调整后的第二天我们重新抓包确认两个方向上都没有再出现Retransmission和Out-of-Order接口超时也随之消失。复盘时大家有个共识这类问题如果一开始就在两端同时抓包用时间轴对比同一个TCP流里的序列号变化可能半小时就能定位不用拖两天。于是团队后来定了一条很土但有效的规则任何“间歇性超时”问题如果排查半小时还没结论就上Wireshark抓包不要继续靠加日志、重启服务来试探。抓包给出的不是“哪里有错”的结论而是一条能顺着推到底的证据链这才是我觉得它最值钱的地方。6. 新手最容易踩的坑以及我的绕坑方案6.1 HTTPS抓包只见“TCP TLS”看不到请求内容怎么办现在大多数流量都是HTTPS很多新手费劲抓到包后发现HTTP层是空的只有一串TLS握手流程于是觉得Wireshark没用。实际上对于自己可以控制的客户端环境可以通过TLS会话密钥导出机制来看明文内容。到Wireshark的Preferences - Protocols - TLS里配置密钥文件位置配合客户端的SSLKEYLOGFILE环境变量就能解出TLS流量里的HTTP请求和响应。以Linux下启动浏览器为例export SSLKEYLOGFILE/tmp/sslkeys.log firefox然后把这个日志文件路径填到Wireshark的TLS设置里即可。这个功能的意义在于它把“HTTPS看不到内容”这个黑盒重新打开了。但必须强调密钥文件相当于流量内容的钥匙任何拿到它的人都能解密对应流量所以只能在可信的、自有的环境里使用用完及时关闭也不要把别人的流量拿来练手。6.2 抓包文件越来越大的另类解法图形界面打开几个GB的抓包文件滚动一下都卡顿。我的建议是抓包阶段就做好规划不需要的协议在捕获过滤器里直接滤掉比如组播、ARP这些噪声持续监控用多文件轮转。分析阶段如果遇到超大文件优先用命令行工具而不是强行双击打开。比如列出一堆异常包tshark -r capture.pcapng -Y tcp.analysis.retransmission -T fields -e frame.number -e ip.src -e tcp.stream这条命令会输出所有重传包的编号、来源IP和TCP流ID先用命令行把可疑流缩小到几条再用图形界面加载同样的大文件也会变得有方向。不要一上来就让图形界面处理所有流量这是经验之谈。6.3 看到重传就说是丢包其实不一定新手最容易过度解读两个词一个是“TCP Retransmission”一个是“Out-of-Order”。一看到重传就断定网络丢包这往往会误导后续操作。实际上网络延迟抖动、多路径导致包乱序、接收窗口动态变化都可能触发快速重传。而Wireshark标记的“Previous segment lost”有时候只是阶段性乱序并不是真正丢包。最稳妥的判断方法是两端同时抓包。把同一个TCP流的序列号在客户端和服务端的抓包里做对比看丢失的包是不是一个方向完全没收到、另一个方向也没有确认。只有这种双向对比才能把结论落在更可靠的位置上。抓包工具的职责永远是呈现数据而不是替你下结论。你在排障时越早习惯这一点就越不会被表面标记带偏。