TCP重传是网络排障中最常见的异常信号之一。当我们在业务上感受到接口偶发变慢、SSH连接卡顿或者长连接莫名断开时,抓包看一眼有没有重传,往往能比看监控更快地接近问题本质。tcpdump作为最轻量的抓包工具,几乎可以在任何Linux服务器上直接使用,本文就来聊聊如何用tcpdump抓取并分析TCP重传报文。

一、TCP重传是怎么发生的
要分析重传,先得理解重传产生的机制。TCP是一种可靠传输协议,发送方每发出一个数据段,都会启动一个重传定时器(RTO,Retransmission Timeout)。如果在定时器超时之前没有收到对端的ACK确认,发送方就会认为这个报文在传输过程中丢失了,于是重新发送一次,这就是最基本的超时重传。
除了超时重传,还有一种更常见的快速重传。当接收方收到一个失序的报文时,会重复发送对最后一个连续序号的ACK,发送方连续收到三个重复ACK(dup ack)后,不需要等到超时,就会立刻重传对应序号的报文段。快速重传的触发条件比超时重传宽松得多,所以在实际抓包中,快速重传的出现频率通常远高于超时重传。
需要注意的是,重传本身不等于故障。互联网链路上有万分之一的丢包率都属正常,少量重传是TCP自我修复的正常行为。真正需要警惕的是重传率明显升高,比如重传包占总数据包的比例超过百分之一,或者短时间内出现密集的超时重传,这通常意味着链路质量恶化或链路拥塞严重。
二、用tcpdump抓取重传相关的报文
tcpdump本身没有直接的retransmission过滤关键字,这点和Wireshark不同。Wireshark可以在过滤器里直接写tcp.analysis.retransmission,而tcpdump需要依靠tcp协议头的标志位、序列号等信息配合过滤。最常用的做法是先用宽松条件把包抓下来,再用Wireshark离线分析,或者直接观察tcpdump输出中的特征。
一个比较实用的抓包命令如下:
# 抓取与指定IP之间80端口的报文,写入文件供离线分析 tcpdump -i eth0 host 192.168.1.100 and port 80 -w /tmp/retrans.pcap -s 0 # 直接在控制台观察,附带相对序列号和ACK号,方便人工比对 tcpdump -i eth0 -tttt -nn -tttt tcp and host 192.168.1.100
几个参数的含义值得说明。-s 0表示抓取完整报文而不是默认的96字节截断,这对分析TCP头部很重要;-tttt显示带日期的详细时间戳,方便统计重传的时间分布;-nn禁止域名和端口反向解析,减少抓包时的性能损耗。如果是在生产环境抓包,建议加上-c 100000限制抓包数量,或者用-G 60做轮转,避免pcap文件把磁盘写满。
如果只想快速看到疑似重传,可以直接过滤RST包和明显异常的报文,例如tcp[13]&4!=0可以匹配TCP标志位中RST置位的包。RST不等于重传,但频繁RST往往伴随连接异常,值得一起观察。
三、如何从输出中识别重传
拿到pcap文件后,用Wireshark打开,在过滤栏输入tcp.analysis.retransmission可以列出所有超时和快速重传的报文,输入tcp.analysis.duplicate_ack可以列出重复ACK,输入tcp.analysis.fast_retransmission则专门看快速重传。这三类报文组合起来,基本能还原丢包的全貌。
如果不方便用Wireshark,也可以直接阅读tcpdump的文本输出。开启相对序列号(tcpdump默认就是相对序号)后,重传的特征是:同一方向出现了两个序号、长度、标志位完全相同的数据包。看下面这段输出:
14:20:01.102345 IP 10.0.0.2.54321 > 10.0.0.3.80: Flags [P.], seq 1000:2000, ack 500, win 256, length 1000 14:20:01.112345 IP 10.0.0.3.80 > 10.0.0.2.54321: Flags [.], ack 500, win 227, length 0 14:20:01.302456 IP 10.0.0.2.54321 > 10.0.0.3.80: Flags [P.], seq 1000:2000, ack 500, win 256, length 1000
第一行发送了seq 1000:2000的数据,第三行在约200毫秒后又发送了一模一样的数据段,且中间对端只回了一个ack 500(说明数据没到),这就是一次典型的超时重传。两个包的时间差约等于当时的RTO值,如果连续出现多轮间隔翻倍的重传(200ms、400ms、800ms),说明丢包持续存在,指数退避生效,情况比较严重。
区分快速重传则看它前面是否紧跟着三个重复的ACK。快速重传间隔通常只有几毫秒到几十毫秒,响应很快,对业务影响相对小;而超时重传动辄几百毫秒的等待,会直接体现在接口耗时上。分析时把这两类分开统计,能更准确评估问题严重程度。
四、判断重传的源头在哪一侧
抓到重传后,更重要的是定位丢包发生在哪一段链路。判断方法很简单:看是谁在重传。如果是客户端方向在重传,说明客户端发出的包丢了或者服务端的ACK没回来;如果是服务端方向在重传,则是服务端发出的数据在路上丢了。在机房内网环境里,两端各自抓包对比是最有效的手段:如果客户端发出去了但服务端没收到,问题在中间链路;如果服务端收到了但ACK没回到客户端,问题在回程链路。
常见的几类原因可以按方向归纳。出方向重传多见于出口带宽跑满、网卡队列丢包、防火墙会话表溢出;入方向重传则可能是服务端负载过高、listen队列或accept不及时导致SYK丢失、内核参数不合理。检查时可以配合netstat -s | grep -i retrans查看系统级重传计数,配合ethtool -S eth0 | grep -i drop查看网卡丢包计数,再与抓包结果交叉验证。
另外有一种容易被误判的情况:服务端慢导致的伪重传。当服务端处理不过来、ACK回得很慢时,客户端RTO超时就会重传,实际上对端最终收到了两次相同数据并丢弃一份。这种场景下重传包很多但链路本身没丢包,优化方向应该是服务端性能而不是网络。通过在服务端同时抓包确认数据是否到达,就能把这两种情况区分开,避免在错误的方向上浪费时间。
五、分析时的几点实用建议
第一,抓包前先明确范围。用host、port限定五元组,避免全量抓包带来的性能开销和海量无关数据。生产环境全量抓TCP包,千兆网卡每秒可产生上万个包,pcap文件几分钟就能到几个GB,定位起来反而更困难。
第二,注意时间同步。如果要在多台机器上同时抓包对比,务必保证各机器NTP对时准确,否则时间戳对不上,推断丢包位置时会得出错误结论。内网NTP偏差控制在毫秒级比较稳妥。
第三,结合统计工具量化问题。tcpdump配合shell可以粗略统计重传率,例如用capinfos查看总包数,再用Wireshark的统计功能看重传包数,重传率等于重传包数除以总数据包数。有了量化数据,向网络团队或云服务商提工单时也更有说服力。
总的来说,tcpdump抓包分析TCP重传的核心思路是:抓到完整报文、识别重复序号、统计重传率、判断丢包方向,再结合系统计数器交叉验证。熟练掌握这套流程后,大部分网络延迟和抖动类问题都能在几十分钟内定位到大致范围,为后续的精细化排查打下基础。