协议基石:TCP重传机制详解(超时重传、快速重传、SACK)
聊重传风暴之前,咱们得先把地基打牢。TCP的重传机制,说白了就是“丢了包怎么办”的那套规矩。我见过不少运维兄弟,一看到重传就慌,其实你只要搞懂这三种机制,定位问题就有方向了。
一、超时重传(RTO)——最原始,也最“笨”
超时重传是TCP最朴素的保底手段。发送方扔出去一个数据包,就启动一个定时器。如果定时器到期了还没收到ACK,那就默认包丢了,重新发一次。
核心参数:RTO(Retransmission Timeout)
RTO不是拍脑袋定的,它基于RTT(往返时间)动态计算。公式大致是:
RTO = SRTT + max(G, 4 * RTTVAR)
其中SRTT是平滑后的RTT,RTTVAR是RTT的偏差。说白了,网络越抖,RTO就越大。
我遇到过一个问题:某业务偶尔出现几秒的卡顿,抓包一看,RTO被算到了3秒多。为什么?因为网络偶尔抖动一下,RTT突然飙高,RTO就被撑大了。结果丢包后要等3秒才重传,用户体验能不差吗?
避坑指南:RTO最小值
我曾经在Linux内核里调过参数,默认RTO最小值是200ms(HZ=100时是200ms,HZ=250时是200ms)。但有些内核版本或云厂商的定制内核,这个值可能被改过。如果你发现重传间隔异常短(比如几十毫秒),先查一下这个:
sysctl net.ipv4.tcp_rto_min
太小了容易误重传,太大了延迟高。我个人习惯在数据中心内部网络设成100ms,公网环境保持默认。
二、快速重传——比超时更“聪明”
超时重传有个硬伤:它要等。等RTO到期,这段时间可能已经够传好几个包了。快速重传的思路是——不等定时器,用ACK来触发。
接收方收到乱序包时,会重复确认上一个期望的序号。发送方收到3个重复的ACK(DupACK),就认为包丢了,不等超时直接重传。
为什么是3个?
不是拍脑袋定的。1个DupACK可能是乱序,2个也可能是乱序,3个基本可以排除乱序的偶然性。我在项目里见过有人想改成2,结果误重传率飙升,后来又改回来了。嗯,TCP的默认值,大多数时候别乱动。
快速重传的流程,我画了张图,你一看就明白:
三、SACK(选择性确认)——精准打击
快速重传有个问题:它只知道哪个包丢了,但不知道丢了几个。比如你发了1、2、3、4、5,接收方只收到了1、2、5,它只能重复ACK=3。发送方重传了3,但4丢没丢?不知道。还得等下一个DupACK或者超时。
SACK解决了这个问题。接收方在ACK里带上SACK选项,告诉发送方:“我收到了哪些不连续的数据块”。发送方一看就明白,哪些需要重传,哪些已经安全到达。
| 特性 | 超时重传 | 快速重传 | SACK |
|---|---|---|---|
| 触发条件 | RTO定时器到期 | 收到3个DupACK | 收到带SACK信息的DupACK |
| 重传粒度 | 一个包 | 一个包 | 多个包(精准选择) |
| 效率 | 低(等待时间长) | 中(可能多传) | 高(只传丢失的) |
| 适用场景 | 所有场景(保底) | 少量丢包 | 批量丢包、高延迟链路 |
实战建议:
我建议你在生产环境一定要开启SACK。Linux默认是开的:
sysctl net.ipv4.tcp_sack
# 返回1表示开启
但有些老旧设备或者安全策略会关掉它。如果发现重传效率低,先查这个。我曾经帮一个客户排查,他们公网链路丢包率不到1%,但重传风暴却频繁触发。最后发现是中间防火墙把SACK选项给过滤了,导致每次丢包都要等超时。开了SACK之后,重传量直接降了70%。
四、三种机制如何协同工作?
这三种机制不是互斥的,而是配合使用的。我总结了一个优先级:
- SACK优先:如果双方都支持SACK,丢包后先走SACK快速重传,精准恢复。
- 快速重传兜底:如果SACK不可用,靠DupACK触发快速重传。
- 超时重传保底:如果快速重传也没触发(比如ACK也丢了),最终靠RTO超时来恢复。
你想想看,如果网络里突然出现大量重传,先别急着怀疑是超时重传。大多数情况下,快速重传和SACK已经把能处理的丢包都处理了。真正引发风暴的,往往是那些连SACK都救不了的场景——比如接收窗口满了、对端宕机了、或者中间设备把包给静默丢弃了。
注意:重传不等于风暴
单次重传是正常的,TCP本来就有这个设计。但如果你看到重传比例超过1%,或者重传间隔越来越短(比如从200ms降到100ms再降到50ms),那就要警惕了。这叫“指数退避失效”,是重传风暴的前兆。下一章我们会详细讲这个。
五、抓包怎么看?
我习惯用tcpdump抓包,然后用Wireshark分析。这里给几个关键过滤表达式:
# 只看重传包
tcp.analysis.retransmission
# 只看快速重传
tcp.analysis.fast_retransmission
# 只看SACK
tcp.options.sack
嗯,记住一点:Wireshark标记的“重传”是基于序列号和时间的启发式判断,不一定100%准确。但作为第一道筛查手段,够用了。
好了,TCP重传的三种机制就讲到这里。搞懂了这些,你再看重传风暴,就不会一头雾水了。说白了,风暴就是这些机制在某些极端条件下“失控”了。怎么失控的?怎么治?我们后面慢慢聊。