TCP 超时重传机制是为了解决什么问题?
- 标签:网络
🏛 业务架构师
超时重传解决的是**"发出去了但对方没收到"的不确定性**:数据或 ACK 丢失时,发送方在 RTO(超时时间)内没等到确认,就重传该报文段。RTO 根据 RTT 动态估算(平滑 RTT + 波动方差),网络越抖,RTO 越保守。
业务视角我想讲透"重试"这个更普遍的命题——TCP 的做法给业务系统三条直接可抄的经验:
- 重试要有自适应间隔:TCP 连续重传时采用指数退避(RTO 翻倍)。业务调用重试同样必须退避 + 抖动(jitter),否则下游故障恢复的瞬间被齐刷刷的重试打回崩溃——重试风暴把故障放大的案例,每个大促都在发生;
- 重试要有预算上限:TCP 限制重传次数,超过即断开连接。业务重试要限定次数与总耗时预算(重试 3 次、总预算 2 秒),超预算快速失败,把"等到底"改为"报错给用户/降级"——用户宁可看到失败提示,也不想面对 30 秒的转圈;
- 区分"没收到"和"收到了没回":TCP 有快速重传(收到 3 个重复 ACK 就立刻重传,不等超时)。业务上对应"旁路信号触发提前动作":MQ 的死信回执、健康检查失败立即摘流,别等超时这个最慢的信号。
架构引申:微服务调用链上每一层都有重试(网关、RPC、DB 驱动),重试倍乘会让一次请求放大成几十次——链路要统一重试预算、只在最外层或最内层重试。超时与重传是 TCP 的生存机制,预算化、退避化、去放大是它在业务侧的正确翻译。
🏗 系统架构师
TCP 超时重传解决的是报文在网络中丢失(或损坏被丢弃)后,接收方永远等不到、发送方永远不知道的问题——IP 层只管尽力交付不管确认,可靠性必须由端到端的传输层自己构建,超时重传就是这个可靠性的发动机。
机制细节:
- 每发出一个报文段启动重传计时器,RTO(超时时间)内未收到对应 ACK 就重传;
- RTO 不能拍固定值:RTT 随网络波动,TCP 用 RTT 采样 + 指数加权移动平均(EWMA) 估计平滑 RTT 和 RTT 波动方差,动态计算 RTO(经典 Jacobson 算法,RTO = SRTT + 4×RTTVAR);
- 每次重传超时翻倍(指数退避),避免网络已经拥塞还穷追猛打;连续多次重传失败则断开连接;
- 快速重传作为补充:连续收到 3 个重复 ACK 就立即重传,不必干等超时——超时是"兜底",快速重传是"主力"。
架构启发:这套"动态超时估算 + 指数退避 + 快速失败"是所有分布式重试设计的母版:我设计 RPC 重试、MQ 消费重试、HTTP 调用超时配置时,全部沿用同样的模式,重试策略本质上是把 TCP 的对抗丢包经验泛化到应用层。
💻 全栈开发专家
解决的问题:IP 层不可靠(丢包、乱序、重复)之下的"可靠送达"。发出去的包没等到 ACK,就重发,这是 TCP 可靠性的基石之一。
机制要点:
- RTO 自适应:内核采样 RTT(
SRTT平滑值 +RTTVAR波动),重传超时 RTO 按公式计算,网络变差自动拉长。 - 超时重传 + 指数退避:第一次超时重传后 RTO 翻倍(1s → 2s → 4s...),避免雪上加霜。
- 快速重传:不等超时——收到 3 个重复 ACK 立刻重传丢失段(SACK 选择性确认更精准),这是性能主力,超时重传是最后防线。
- 重传后触发拥塞控制(cwnd 减半/降为 1),从"保证送达"延伸到"别打死网络"。
工程排查(我处理"接口偶发 1s+ 延迟"的套路):
bash
netstat -s | grep -i retrans # 看 TCP 重传次数(Retransmits)
ss -ti dst 10.0.0.5 # 看具体连接的 rto/rtt/retrans 统计重传率 = retrans/segs,超过 1% 就要查网络(跨机房链路、网卡丢包、超卖虚拟机);超时重传第一次的 RTO 至少 200ms~1s,正好对上业务日志里"偶发 1s 慢请求"的现象——很多"玄学慢"其实是 TCP 层重传。