飞翔飞翔
主页
  • 计算机基础

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • TCP协议

    • TCP 简介与分层模型
    • TCP 连接管理
    • TCP 可靠传输机制
    • TCP 粘包与拆包
    • TCP 拥塞控制
    • TCP 头部字段详解
    • TCP 与 UDP 对比
    • TCP Socket 编程实践
    • TCP 抓包实战
    • TCP 安全与面试综合题

TCP 拥塞控制

网络不是无限大的管道。TCP 如何感知网络拥塞并优雅降速?


1. 什么是拥塞?为什么要控制?

拥塞:太多数据注入网络,超过了路由器/链路的处理能力,导致丢包和延迟增加。

TCP 的拥塞控制回答两个关键问题:

  • 如何发现拥塞? → 丢包(超时或重复 ACK)是主要信号
  • 发现后怎么做? → 降低发送速率,再慢慢恢复

RFC 5681 定义了四个经典拥塞控制算法,RFC 9293 引用这些算法作为 TCP 拥塞控制的基础。


2. 核心概念:拥塞窗口(cwnd)

发送方维护一个拥塞窗口(cwnd),限制已发送但未确认的数据量:

实际可发送量 = min(cwnd, rwnd)

cwnd 以字节为单位,初始值通常为 1-10 MSS。cwnd 动态变化,反映网络状况。


3. 四个经典算法

3.1 慢启动(Slow Start)

名称有误导性——其实并不慢,cwnd 呈指数增长。

触发时机:连接刚建立 或 超时重传发生后。

规则:

  • cwnd 初始值 = IW(Initial Window,通常 1-10 MSS)
  • 每收到一个 ACK,cwnd += 1 MSS
  • 每个 RTT,cwnd 翻倍(指数增长)
RTT 1: cwnd = 1 MSS  →  发 1 个段
RTT 2: cwnd = 2 MSS  →  发 2 个段
RTT 3: cwnd = 4 MSS  →  发 4 个段
RTT 4: cwnd = 8 MSS  →  发 8 个段
...

何时停止?

  • cwnd ≥ ssthresh(慢启动阈值)→ 进入拥塞避免
  • 发生丢包 → cwnd 减半(或重置),进入恢复

3.2 拥塞避免(Congestion Avoidance)

cwnd 超过 ssthresh 后,增速放缓为线性增长。

规则:每个 RTT cwnd += 1 MSS(大约)。实际实现中常用:每收到 ACK,cwnd += MSS × MSS / cwnd。

RTT 5: cwnd = 9 MSS
RTT 6: cwnd = 10 MSS
RTT 7: cwnd = 11 MSS
...

3.3 快速重传(Fast Retransmit)

不需要等 RTO 超时。连续收到 3 个重复 ACK(即 4 个相同 ACK),发送方立即重传丢失的段。

发送方发了 seq: 1  2  3  4  5
                  ↓  X  ↓  ↓  ↓
接收方收到:       1     3  4  5
                  ack=2 ack=2 ack=2 ack=2  (重复 ACK)
                               ↑
                          第 4 个相同 ACK → 快速重传 seq=2

为什么是 3 个?因为少量重复 ACK 可能只是乱序而非丢包,3 个是经验和统计的平衡。

3.4 快速恢复(Fast Recovery)

快速重传后不会退回慢启动(那太慢了),而是执行快速恢复:

  1. ssthresh = cwnd / 2
  2. cwnd = ssthresh + 3 × MSS(补偿已经离开网络的 3 个段)
  3. 每收到一个重复 ACK,cwnd += 1 MSS(保持数据流动)
  4. 收到新 ACK 后,cwnd = ssthresh,进入拥塞避免

4. 算法状态转换图

                    连接建立 / 超时重传
                          ↓
                    ┌──────────┐
                    │  慢启动   │
                    └────┬─────┘
                    cwnd≥ssthresh
                          ↓
                    ┌──────────┐
              ┌────→│ 拥塞避免  │←──────────┐
              │     └────┬─────┘            │
              │    3 dup ACK          收到新ACK │
              │          ↓                  │
              │    ┌──────────┐             │
              │    │ 快速重传  │             │
              │    └────┬─────┘             │
              │         ↓                   │
              │    ┌──────────┐             │
              └────│ 快速恢复  │─────────────┘
                   └──────────┘

5. BBR 简介

BBR(Bottleneck Bandwidth and Round-trip propagation time)是 Google 在 2016 年提出的新一代拥塞控制算法,已纳入 Linux 内核。

与传统算法的区别

维度传统(CUBIC/Reno)BBR
拥塞信号丢包(被动反应)带宽+延迟(主动探测)
窗口调整基于丢包 AIMD基于 BDP 模型
缓冲区倾向于填满(bufferbloat)尽量不填满
适用场景一般网络高延迟、有一定丢包的网络

BBR 的核心思想:不再用丢包作为唯一拥塞信号,而是持续测量瓶颈带宽和最小 RTT,计算出 BDP(带宽延迟积),让 inflight 数据保持在 BDP 附近,既不浪费带宽也不填满缓冲区。


6. 小结

TCP 拥塞控制经历了数十年演进:

  1. Tahoe(1988):慢启动 + 拥塞避免 + 快速重传
  2. Reno(1990):加入快速恢复
  3. NewReno(1999):改进快速恢复
  4. CUBIC(2008):Linux 默认,改线性为三次函数
  5. BBR(2016+):基于模型而非丢包

拥塞控制是 TCP 性能的灵魂。理解了它,你就能理解为什么网络时快时慢,以及如何调优。


本篇要点

  • 拥塞控制保护网络,流量控制保护接收方;实际发送量 = min(cwnd, rwnd)
  • 慢启动:cwnd 指数增长(每个 RTT 翻倍),名字有误导性,其实增长很快
  • ssthresh 是慢启动阈值:cwnd < ssthresh 走慢启动(指数),≥ ssthresh 走拥塞避免(线性)
  • 快速重传:收到 3 个重复 ACK 立即重传丢失段,不必等 RTO 超时
  • 快速恢复:重传后 cwnd 减半而非归零,直接进入拥塞避免(不回慢启动)
  • 超时重传 vs 快速重传:超时说明网络严重拥塞(cwnd 重置+慢启动),快速重传说明轻微丢包(cwnd 减半+快速恢复)
  • BBR 不依赖丢包信号,通过测量瓶颈带宽和最小 RTT 计算最优发送速率,解决 bufferbloat 问题
上一页
TCP 粘包与拆包
下一页
TCP 头部字段详解