高 困难
TCP拥塞控制#
一句话答案#
TCP 拥塞控制四个阶段:慢启动(指数增长)→ 拥塞避免(线性增长)→ 快重传(3 个重复 ACK 立即重传)→ 快恢复(窗口减半而非重置),核心原则是 AIMD(加性增、乘性减)。
核心要点
核心变量#
- cwnd(拥塞窗口):发送方维护,控制发送速率
- ssthresh(慢启动阈值):慢启动和拥塞避免的分界线
- 发送窗口 = min(cwnd, rwnd)
1. 慢启动(Slow Start)#
cwnd 从 1 MSS 开始,每收到一个 ACK → cwnd += 1
效果:每个 RTT cwnd 翻倍(指数增长)
当 cwnd >= ssthresh → 进入拥塞避免plaintext“慢”是相对于一次性发全部窗口,实际增长是指数级。
2. 拥塞避免(Congestion Avoidance)#
cwnd >= ssthresh 后:每个 RTT → cwnd += 1 MSS(线性增长)
直到检测到丢包plaintext3. 快重传(Fast Retransmit)#
收到 3 个重复 ACK → 立即重传丢失的包(不等超时定时器)plaintext4. 快恢复(Fast Recovery)#
3 个重复 ACK 后:ssthresh = cwnd/2, cwnd = ssthresh + 3
→ 进入拥塞避免
对比超时:ssthresh = cwnd/2, cwnd = 1
→ 回到慢启动plaintext区别: 3 重复 ACK → 网络还行只是丢了部分 → 减半。超时 → 可能严重拥塞 → 重置。
状态转换#
cwnd < ssthresh cwnd >= ssthresh
┌─────────┐ ┌──────────┐
│ 慢启动 │─────────────→│ 拥塞避免 │
│ 指数增长 │ │ 线性增长 │
└────┬────┘ └────┬─────┘
│ │
超时丢包 │ 3个重复ACK │
cwnd=1 │ cwnd=cwnd/2 │
回到慢启动 │ 快恢复→拥塞避免 │plaintext常见算法#
| 算法 | 特点 |
|---|---|
| Reno | 经典实现(加入快恢复) |
| Cubic | 基于三次函数增长,Linux 默认 |
| BBR | Google 推出,基于带宽/RTT 估算,不依赖丢包 |
面试回答(2分钟版)
TCP 拥塞控制的目标是防止发送方把网络打满,核心思想是 AIMD 即加性增乘性减。发送方维护一个拥塞窗口 cwnd,实际发送量取 cwnd 和接收方通告窗口 rwnd 的最小值。拥塞控制分四个阶段协同工作:慢启动阶段 cwnd 从 1 个 MSS 开始每收到一个 ACK 就加 1,效果是每个 RTT 翻倍呈指数增长,虽然叫”慢”但增长其实很快。当 cwnd 达到慢启动阈值 ssthresh 后进入拥塞避免阶段,改为每个 RTT 只加 1 个 MSS 做线性增长,试探网络容量。如果检测到丢包,处理策略取决于丢包信号:收到 3 个重复 ACK 触发快重传立即重传丢失的包,然后进入快恢复将 ssthresh 和 cwnd 都减半再线性增长,因为 3 个重复 ACK 说明网络还能通只是丢了部分;如果是超时则认为网络严重拥塞,ssthresh 减半但 cwnd 直接重置为 1 回到慢启动。Linux 默认使用 Cubic 算法基于三次函数增长,Google 的 BBR 算法则不依赖丢包而是基于带宽和 RTT 估算来控制发送速率。
追问与易错
追问方向:
- “慢启动为什么叫’慢’?”→ 相比一次发全部窗口,从 1 开始是”慢”的
- “拥塞控制和流量控制的区别?”→ 流量控制保护接收方(rwnd),拥塞控制保护网络(cwnd)
易错点:
- ❌ “慢启动增长很慢”——指数增长其实很快
- ❌ “丢包就回到慢启动”——3 重复 ACK 是快恢复(减半),超时才是慢启动(重置)