面试知识库
困难

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(线性增长)
直到检测到丢包
plaintext

3. 快重传(Fast Retransmit)#

收到 3 个重复 ACK → 立即重传丢失的包(不等超时定时器)
plaintext

4. 快恢复(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 默认
BBRGoogle 推出,基于带宽/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 是快恢复(减半),超时才是慢启动(重置)