TCP 拥塞控制算法演进全解:从 Tahoe 到 BBRv3 原理、性能与 Linux 实操

🔊

TCP 拥塞控制是网络传输性能的关键决定因素,也是互联网稳定运行的基石。无论是 Web 服务的页面加载速度、视频直播的流畅度、云原生应用的容器间通信,还是 P2P 传输的下载效率,底层都依赖 TCP 拥塞控制协调带宽分配。例如,一个 BitTorrent 节点可能同时维持数百个 TCP 连接,如果算法选择不当,带宽利用率会大幅下降。自 1988 年 Van Jacobson 在 SIGCOMM 上发表经典论文以来,拥塞控制算法经历了近四十年的演进,从基于丢包的启发式方法发展到基于网络模型测量的精确控制。本文梳理 12 种主要拥塞控制算法的核心思想、优缺点与适用场景,从 Tahoe、Reno 到 CUBIC、BBR、Copa。

拥塞控制的基本原理

所有 TCP 拥塞控制算法都围绕拥塞窗口(CWND,Congestion Window)进行工作——它表示发送端在未收到确认前可以发送的最大数据量:

1
吞吐量 ≈ min(CWND, 接收窗口) / RTT

这个公式揭示了 TCP 吞吐量的两个约束:发送端窗口(CWND)和接收端窗口(Receiver Window),两者中的较小者决定了实际吞吐量。CWND 由拥塞控制算法动态调整,而接收窗口由接收端的缓冲区大小决定。

不同算法的核心差异体现在三个维度:

  1. CWND 增长速度(慢启动 vs 拥塞避免)——决定了连接启动和带宽探测的效率
  2. 拥塞检测信号(丢包 vs 延迟 vs 带宽测量)——决定了算法对网络状态的感知方式
  3. 拥塞后的降速策略(乘法减小 vs 模型驱动的调整)——决定了拥塞事件后的恢复速度
mermaid
flowchart TD
    A["连接建立<br/>CWND = IW"] --> B["慢启动<br/>CWND 每 RTT 翻倍"]
    B -->|"CWND &#8805; ssthresh"| C["拥塞避免<br/>CWND 每 RTT +1 MSS"]
    C -->|"丢包 / 超时"| D{"信号类型"}
    D -->|"3 重复 ACK"| E["快重传 + 降速"]
    D -->|"超时"| F["CWND = 1<br/>重回慢启动"]
    E --> C
    F --> B
    style A fill:#2196F3,color:#fff
    style B fill:#2196F3,color:#fff
    style C fill:#4CAF50,color:#fff
    style D fill:#9C27B0,color:#fff
    style E fill:#FF9800,color:#fff
    style F fill:#f44336,color:#fff

上图展示了所有 TCP 拥塞控制算法的共同框架:慢启动 → 拥塞避免 → 丢包响应。不同算法的核心差异在于

TCP Tahoe(1988)

Van Jacobson 在 1988 年 SIGCOMM 论文中提出的拥塞控制框架,后来被称为 TCP Tahoe。Tahoe 定义了拥塞控制的三个核心阶段:

  • 慢启动(Slow Start):连接建立后,CWND 从初始窗口(通常为 10 个报文段)开始,每收到一个 ACK 增加 1 个 MSS,实现指数级增长,快速探测可用带宽。
  • 拥塞避免(Congestion Avoidance):当 CWND 达到慢启动阈值(ssthresh)后,每个 RTT 仅增加 1 个 MSS,转为线性增长,谨慎利用带宽。
  • 快重传(Fast Retransmit):收到 3 个重复 ACK 时立即重传丢失报文,无需等待超时。

Tahoe 的局限在于发生丢包后,它直接降为慢启动(CWND = 1 MSS),每次丢包都要从头探测带宽。在高带宽链路上,这意味着大量的带宽浪费和恢复时间。这一缺陷直接催生了 Reno 的诞生——Reno 引入的快恢复机制,避免了丢包后重新慢启动的低效。

TCP Reno(1990)

Reno 在 Tahoe 的基础上增加了**快恢复(Fast Recovery)**机制,形成了完整的 AIMD(Additive Increase Multiplicative Decrease)模型。它的核心思想可以用一句话概括:轻负载时线性增长,检测到拥塞时指数退避

mermaid
flowchart TD
    SS["慢启动<br/>CWND = IW<br/>指数增长"] -->|"CWND ≥ ssthresh"| CA["拥塞避免<br/>每 RTT +1 MSS<br/>线性增长"]
    CA -->|"丢包"| LOSS{"信号类型"}
    LOSS -->|"3 重复 ACK"| FR["快恢复<br/>ssthresh = CWND/2"]
    LOSS -->|"超时"| TO["超时<br/>ssthresh = CWND/2<br/>CWND = 1"]
    FR -->|"新 ACK"| CA
    TO --> SS
    style SS fill:#2196F3,color:#fff
    style CA fill:#4CAF50,color:#fff
    style LOSS fill:#9C27B0,color:#fff
    style FR fill:#FF9800,color:#fff
    style TO fill:#f44336,color:#fff

Reno 的慢启动阶段以指数方式快速探测可用带宽——每收到一个 ACK,CWND 增加一个 MSS(最大报文段长度),相当于每个 RTT 翻倍。当 CWND 达到慢启动阈值(ssthresh)后,进入拥塞避免阶段,每个 RTT 只增加 1 个 MSS,形成线性增长。一旦检测到丢包(三个重复 ACK),立即将 ssthresh 设为当前 CWND 的一半,CWND 也降到 ssthresh,进入快恢复阶段。

Reno 经典 AIMD 锯齿波拥塞窗口演化

Reno 的局限:在高带宽高延迟链路(如跨洋光纤)上表现保守。假设一条 100ms RTT、1Gbps 带宽的链路,BDP 约为 12.5MB。如果发生丢包,CWND 减半后需要数千个 RTT 才能恢复到原窗口大小——这意味着数分钟的恢复时间,严重浪费带宽。

TCP Vegas(1994)

Vegas 由 Brakmo 和 Peterson 提出,是第一个基于延迟的拥塞控制算法,标志着拥塞控制从"反应式"向"预测式"的转变。

Vegas 通过监测 RTT 的变化来估计网络排队情况,在丢包发生之前就主动调整发送速率。它维护两个关键测量值:BaseRTT(观测到的最小 RTT,代表无排队延迟)和 CurrentRTT(当前实测 RTT)。通过比较期望吞吐量和实际吞吐量的差异来判断网络拥塞程度:

$$ Diff = \left(\frac{CWND}{BaseRTT} - \frac{CWND}{CurrentRTT}\right) \times BaseRTT $$

当 Diff 小于阈值 α 时,认为带宽充裕,增加 CWND;当 Diff 大于阈值 β 时,认为网络即将拥塞,降低 CWND。α 和 β 的典型值分别为 2 和 4。

mermaid
flowchart TD
    A["测量 RTT<br/>BaseRTT / CurrentRTT"] --> C["计算 Diff<br/>= CWND/BaseRTT &#8722; CWND/CurrentRTT"]
    C --> D{"Diff 值"}
    D -->|"Diff < &#945;"| E["带宽充裕<br/>CWND += 1"]
    D -->|"&#945; &#8804; Diff &#8804; &#946;"| F["稳定 zone<br/>CWND 保持"]
    D -->|"Diff > &#946;"| G["即将拥塞<br/>CWND &#8722;= 1"]
    style A fill:#2196F3,color:#fff
    style C fill:#FF9800,color:#fff
    style D fill:#9C27B0,color:#fff
    style E fill:#4CAF50,color:#fff
    style F fill:#FF9800,color:#fff
    style G fill:#f44336,color:#fff

Vegas 的创新在于实现了拥塞避免的前瞻性——它在队列开始堆积时就做出反应,而不是等到缓冲区溢出导致丢包。这使得 Vegas 在理想条件下能保持极低的排队延迟,避免了传统 AIMD 算法常见的"锯齿波"震荡。

Vegas 延迟探测平滑拥塞窗口演化

然而,Vegas 在与 Reno/CUBIC 等基于丢包的算法共享瓶颈链路时,表现得过于"礼貌"——它会因为自己引入的微小延迟而主动退让,导致带宽被基于丢包的激进流抢占。这一兼容性问题严重限制了 Vegas 的实际部署。

TCP NewReno(1996)

NewReno 由 Floyd 和 Henderson 提出,是对 Reno 快恢复机制的针对性改进,专门解决同一个窗口内发生多次丢包时的性能问题。

Reno 的快恢复存在一个缺陷:当同一窗口内丢失多个报文时,快恢复阶段收到的第一个新 ACK(对应第一个重传报文的确认)会使 Reno 退出快恢复,而此时还有丢失报文未被重传。这导致 Reno 需要反复进入快恢复,每次只能修复一个丢包。

NewReno 的关键改进是引入了部分 ACK 检测逻辑:如果在快恢复期间收到的 ACK 确认了部分但非全部已发送数据(即部分 ACK),NewReno 不会退出快恢复,而是立即重传下一个丢失报文,并保持 CWND 不变。只有当 ACK 确认了快恢复开始时所有未确认数据时,才退出快恢复。

mermaid
flowchart TD
    A["3 个重复 ACK<br/>进入快恢复"] --> B["重传丢失报文"]
    B --> C{"收到 ACK?"}
    C -->|"部分 ACK<br/>仍有数据未确认"| D["重传下一个丢失报文<br/>不退出快恢复"]
    D --> C
    C -->|"完整 ACK<br/>全部数据已确认"| E["退出快恢复<br/>进入拥塞避免"]
    style A fill:#2196F3,color:#fff
    style B fill:#FF9800,color:#fff
    style C fill:#9C27B0,color:#fff
    style D fill:#FF9800,color:#fff
    style E fill:#4CAF50,color:#fff

这种改进使 NewReno 在存在随机丢包的链路上性能显著优于 Reno,且完全在发送端实现,无需接收端做任何修改。NewReno 后来被标准化为 RFC 2582(后更新为 RFC 3782)。

TCP Westwood+(2002)

Westwood+ 由 Mascolo 等人提出,针对无线网络中随机丢包导致的性能下降问题进行了专门优化。其核心思路是使用带宽估计而非简单的丢包信号来调整拥塞窗口。

Westwood+ 通过监测 ACK 到达速率来持续估计可用带宽。当检测到丢包时,它不像 Reno 那样暴力减半 CWND,而是根据估计的可用带宽来计算新的窗口值:

$$ ssthresh = \frac{BWEst \times RTT_{min}}{MSS} $$

Westwood+ 带宽感知拥塞窗口演化

这种带宽感知的降速策略使 Westwood+ 在存在随机丢包的无线链路上表现优异——当丢包由信道噪声而非拥塞引起时,带宽估计值不会显著下降,因此 CWND 不会被过度降低。

Westwood 最初版本仅使用发送端测量,Westwood+ 增加了接收端 ACK 滤波以消除 ACK 压缩(ACK Compression)的影响,使带宽估计更加准确。

BIC(2004)

BIC(Binary Increase Congestion Control)由 Xu、Harfoush 和 Rhee 提出,是针对高带宽长距离网络设计的拥塞控制算法,也是 CUBIC 的前身。

BIC 使用二分搜索来寻找带宽边界。拥塞发生时记录当前窗口 $W_{max}$,恢复阶段在 $W_{min}$(拥塞后窗口值)和 $W_{max}$ 之间进行二分搜索,快速逼近但不超过之前的窗口上限。超过 $W_{max}$ 后,采用最大探测(Max Probing)策略,逐步扩大搜索范围以试探新的带宽上限。

BIC 在高 BDP 网络中表现优秀,但它有两个突出问题:一是窗口函数的形状不平滑——分段二分搜索在不同区域的切换导致窗口抖动;二是在低带宽网络中过于激进,与 Reno 等传统算法共存时缺乏友好性。

BIC 二分搜索拥塞窗口演化

TCP Hybla(2004)

Hybla 由 Caini 和 Firrincieli 提出,专门针对卫星通信等长 RTT 链路的特殊需求设计。

Hybla 的核心观察是:传统 TCP 算法中,长 RTT 连接在拥塞避免阶段的窗口增长速率远低于短 RTT 连接。Hybla 通过引入"RTT 归一化"因子来补偿这种不公平性,模拟理想参考连接的行为,使长 RTT 流获得与短 RTT 流同等的窗口增长速率。

在 GEO 卫星链路(RTT ≈ 500ms)等极端场景下,Hybla 可将吞吐量提升数倍。它的主要局限是参数选择依赖于对链路类型的先验知识,在链路特性动态变化的环境中效果会打折扣。

Hybla RTT 归一化拥塞窗口演化

TCP CUBIC(2005)

CUBIC 是当前 Linux 内核的默认拥塞控制算法,由 Injong Rhee 等人提出,专门为解决 Reno 在高 BDP(带宽延迟积)网络中的低效问题而设计。

立方增长函数

CUBIC 最核心的创新是用一个三次函数来驱动窗口增长:

$$W(t) = C \times (t - K)^3 + W_{max}$$

其中 $t$ 是距离上次拥塞事件的时间,$W_{max}$ 是拥塞发生时的窗口大小,$C$ 是一个缩放常数(默认 0.4),$K = \sqrt[3]{W_{max} \times \beta / C}$ 是窗口恢复到 $W_{max}$ 所需的时间。

mermaid
flowchart TD
    B["W(t) = C×(t&#8722;K)³ + Wmax<br/>t = 距上次拥塞时间"] --> D{"窗口位置"}
    D -->|"Wmax 以下"| E["凹增长<br/>快速追赶原窗口"]
    D -->|"Wmax 以上"| G["凸增长<br/>探测新带宽上限"]
    E --> H{"丢包?"}
    G --> H
    H -->|"是"| I["CWND × 0.7<br/>记录新 Wmax"]
    I --> B
    style B fill:#2196F3,color:#fff
    style D fill:#9C27B0,color:#fff
    style E fill:#4CAF50,color:#fff
    style G fill:#FF9800,color:#fff
    style H fill:#9C27B0,color:#fff
    style I fill:#f44336,color:#fff

CUBIC S 曲线拥塞窗口演化

CUBIC 的三大特性

CUBIC 的核心理念是用时间而非ACK 到达来驱动窗口增长,这意味着窗口增长速率与 RTT 无关:

  • 凹增长:远低于 $W_{max}$ 时快速恢复。丢包发生后,CUBIC 的窗口函数急剧上升,迅速将 CWND 拉回到拥塞前的水平——这正是 Reno 表现最差的区域。
  • 凸增长:超过 $W_{max}$ 后积极探测新高点。当 CWND 超过上次拥塞的窗口值后,函数曲线开始加速,主动寻找新的带宽上限。
  • RTT 公平性:不同 RTT 的流在固定时间内达到相同的窗口增量。在 Reno 中,短 RTT 的流拥塞窗口增长更快,容易"饿死"长 RTT 流。CUBIC 消除了这种 RTT 偏差。

为什么 CUBIC 取代了 BIC

CUBIC 的前身是 BIC(Binary Increase Congestion Control),后者使用二分搜索来探测带宽边界——这种方法在高带宽网络中表现优秀,但在低带宽网络中过于激进,且窗口函数的形状不平滑。CUBIC 用一个平滑的三次函数替代了 BIC 的分段二分搜索,既保留了高 BDP 下的效率,又改善了低带宽网络中的友好性。

DCTCP(2010)

DCTCP(Data Center TCP)由 Alizadeh 等人提出,为数据中心网络量身定制。数据中心的典型特征是高带宽(10Gbps-40Gbps)、低延迟(微秒级)、缓冲区有限,且流量模式以短突发流为主。

DCTCP 的核心创新在于利用 ECN(Explicit Congestion Notification)信号进行精细化拥塞控制。交换机在队列长度超过阈值时标记数据包,DCTCP 接收端统计被标记包的比例 $F$,发送端据此计算拥塞因子 $\alpha$:

$$ \alpha = (1 - g) \times \alpha + g \times F $$

其中 $g$ 是平滑因子(默认 1/16)。发生拥塞时,CWND 设置为 $CWND \times (1 - \alpha/2)$,而不是粗暴减半。这意味着拥塞越严重,降速越激进;拥塞越轻微,降速越平缓。

mermaid
flowchart TD
    A["队列 > 阈值<br/>交换机标记 ECN"] --> C["接收端统计标记比例 F"]
    C --> D["发送端更新拥塞因子<br/>&#945; = (1&#8722;g)&#945; + gF"]
    D --> E{"发生拥塞时"}
    E -->|"轻度 &#945; 小"| F["CWND &#215; (1&#8722;&#945;/2)<br/>微小降低"]
    E -->|"重度 &#945; 大"| G["CWND &#215; (1&#8722;&#945;/2)<br/>大幅降低"]
    style A fill:#2196F3,color:#fff
    style C fill:#FF9800,color:#fff
    style D fill:#FF9800,color:#fff
    style E fill:#9C27B0,color:#fff
    style F fill:#4CAF50,color:#fff
    style G fill:#f44336,color:#fff

DCTCP 的显著效果是实现了低延迟 + 高吞吐的理想组合——在生产环境中,DCTCP 将尾部延迟降低了 90% 以上,同时保持了接近 100% 的链路利用率。但 DCTCP 依赖交换机的 ECN 支持,仅适用于受控的数据中心环境。

DCTCP ECN 感知渐进式拥塞窗口演化

BBR 的范式革命(2016)

Google 在 2016 年发布的 BBR(Bottleneck Bandwidth and Round-trip propagation time)彻底改变了拥塞控制的传统范式。核心洞察是:丢包不等同于拥塞

在无线网络、蜂窝网络等场景中,数据包可能因为信号干扰、信道衰减等原因丢失,但这并不意味着网络链路发生了拥塞。传统基于丢包的算法在这种情况下会错误地降低发送速率,造成严重的带宽浪费。

维度传统丢包算法(Reno / CUBIC)BBR(模型驱动)
观察信号丢包带宽 + RTT
核心假设丢包 = 拥塞测量 BtlBw + RTprop
行为丢包 → 降速在 BDP 点运行
在丢包链路上带宽利用率大幅下降维持高吞吐

丢包 ≠ 拥塞 是 BBR 的出发点:无线网络里数据包常因信号干扰丢失,这时粗暴降速纯属浪费带宽。

BBR 的关键创新

  • 不依赖丢包信号:在丢包率高达 15% 的链路上仍能维持高吞吐,而 CUBIC 在 1% 丢包率时吞吐量就会大幅下降。
  • 主动测量带宽延迟积(BDP):通过测量瓶颈带宽(BtlBw)和传播延迟(RTprop),计算出链路的最佳承载数据量,在 BDP 点运行,既不产生队列也不造成浪费。
  • 避免 Bufferbloat:即使缓冲区很大,BBR 也不会填满缓冲区,从而避免大量排队延迟——这对延迟敏感的应用(如实时音视频、在线游戏)至关重要。

BBR 模型驱动拥塞窗口演化

BBR 版本演进

BBR 自发布以来经历了三个主要版本的迭代:

版本时间核心改进
BBR v12016首次提出基于模型的拥塞控制,实现高吞吐低延迟;但存在与 Reno/CUBIC 共存公平性差、STARTUP 阶段丢包率高的问题
BBR v22019引入 ECN 信号支持,改善与 Reno/CUBIC 共存时的公平性,降低 STARTUP 阶段的丢包率
BBR v32023修复带宽收敛 bug,STARTUP 增益从 2.89 降至 2.77,进一步降低排队延迟,优化短流性能

版本演进的关键驱动力

BBR 的版本演进反映了学术界和工业界对"理想拥塞控制"理解的深化:

  1. 共存公平性:BBR v1 在与其他算法共享瓶颈链路时过于激进,会抢占 CUBIC 流的带宽。v2 和 v3 通过引入更保守的竞争策略逐步改善了这个问题。
  2. STARTUP 阶段的震荡:初始版本中 STARTUP 阶段的指数增益过高(2.89),导致频繁的过度探测和丢包。v3 将增益降到 2.77,显著减少了启动震荡。
  3. 带宽收敛:在多流共享瓶颈的场景中,v1 和 v2 存在带宽分配不稳定的问题。v3 通过算法优化实现了更快、更稳定的收敛。

PCC(2016)

PCC(Performance-oriented Congestion Control)由 Dong 等人提出,与 BBR 同年发布,但采用了截然不同的方法论——将拥塞控制构建为一个在线学习问题。

PCC 不依赖任何关于拥塞信号的先验假设(无论是丢包、延迟还是带宽),而是直接通过试验来优化发送速率。其核心是 Monitor-Compare-Arrange 循环:发送端对一个方向微调发送速率(+Δt),观察效用函数的变化;再向另一个方向微调(-Δt),对比两个方向的结果,选择更优的方向继续调整。

mermaid
flowchart TD
    A["当前速率 r"] --> B["尝试 r + &#916;<br/>测量效用 U&#8314;&#8314;"]
    B --> C["尝试 r &#8722; &#916;<br/>测量效用 U&#8315;"]
    C --> D{"U&#8314;&#8314; > U&#8315;?"}
    D -->|"是"| E["提高速率"]
    D -->|"否"| F["降低速率"]
    E --> A
    F --> A
    style E fill:#4CAF50,color:#fff
    style F fill:#f44336,color:#fff

PCC 的效用函数综合了吞吐量和延迟指标:

$$ U = \frac{Throughput^{\alpha}}{Latency^{\beta}} $$

这种方法的优势是无需对网络行为做任何假设,自动适应各种链路条件。但它的计算开销较大,且收敛速度可能较慢。后续改进版本 PCC Vivace 引入了在线梯度上升算法,显著加速了收敛过程。

Copa(2018)

Copa 由 Arun 和 Balakrishnan 提出,是最新一代的延迟感知拥塞控制算法。它回归了 Vegas 的延迟探测思路,但采用了更加精巧的"载波检测"(Carrier Sensing)机制。

Copa 通过感知排队延迟 $d_{queued}$ 来动态调整发送速率。其核心参数 $\lambda$ 决定了每次 ACK 到来时 CWND 的增加量:

mermaid
flowchart TD
    A["测量排队延迟<br/>d = RTT &#8722; BaseRTT"] --> B["计算增长率<br/>&#955; = &#948; / d"]
    B --> C{"d < 目标延迟?"}
    C -->|"是 延迟低"| D["CWND += &#955;<br/>加速增长"]
    C -->|"否 延迟高"| E["CWND &#8722;= &#955;<br/>主动退让"]
    style D fill:#4CAF50,color:#fff
    style E fill:#FF9800,color:#fff
$$ \lambda = \frac{\delta}{d_{queued}} $$

其中 $\delta$ 是参数(默认值 0.5)。当排队延迟增加时,$\lambda$ 减小,窗口增长变缓;排队延迟减小时,$\lambda$ 增大,增长加快。Copa 的目标是维持一个固定的排队延迟目标(通常对应 5 个 RTT 的排队量)。

Copa 的设计精妙之处在于通过调整增长速率而非机械地升降窗口来实现平滑控制。在测试中,Copa 在吞吐量上与 BBR 相当,同时保持了更低的延迟。它还包含竞争模式,使其在与 CUBIC 等激进流共存时不被饿死。

拥塞控制算法演进时间线

从 1988 年到 2023 年,TCP 拥塞控制算法经历了从无到有、从简单到复杂的演进过程。以下两个时间线图分别展示了早期和现代主要算法的发展脉络:

早期算法(1988—2004)

mermaid
flowchart TD
    T["1988: Tahoe<br/>慢启动 + 拥塞避免<br/>快重传"]
    R["1990: Reno<br/>+ 快恢复<br/>AIMD 经典"]
    V["1994: Vegas<br/>延迟探测<br/>预测拥塞"]
    N["1996: NewReno<br/>部分 ACK<br/>多丢包修复"]
    W["2002: Westwood+<br/>带宽估计<br/>无线友好"]
    B["2004: BIC<br/>二分搜索<br/>高 BDP 效率"]

    T --> R
    R --> N
    R --> V
    N --> B
    V --> W
    style T fill:#2196F3,color:#fff
    style R fill:#2196F3,color:#fff
    style V fill:#9C27B0,color:#fff
    style N fill:#FF9800,color:#fff
    style W fill:#4CAF50,color:#fff
    style B fill:#f44336,color:#fff

现代算法(2004—2023)

mermaid
flowchart TD
    H["2004: Hybla<br/>卫星链路优化<br/>RTT 补偿"]
    C["2005: CUBIC<br/>三次函数<br/>RTT 无关"]
    D["2010: DCTCP<br/>数据中心<br/>ECN 标记"]
    P["2016: PCC<br/>性能驱动<br/>在线学习"]
    BR["2016: BBR v1-3<br/>模型驱动<br/>BtlBw+RTprop"]
    O["2018: Copa<br/>延迟感知<br/>载波检测"]

    H --> C
    C --> D
    D --> P
    C --> BR
    BR --> O
    style H fill:#2196F3,color:#fff
    style C fill:#2196F3,color:#fff
    style D fill:#FF9800,color:#fff
    style P fill:#9C27B0,color:#fff
    style BR fill:#4CAF50,color:#fff
    style O fill:#9C27B0,color:#fff

从这两个时间线可以清晰看到拥塞控制的发展趋势:从基于丢包的反应式控制,到基于延迟的预测式控制,再到基于模型和性能驱动的智能化控制。这一演进反映了互联网从简单有线网络到复杂异构网络的技术需求变迁。

Linux 实操:查看与切换算法

了解了算法原理后,我们来看看如何在 Linux 系统中实际操作。以下命令可以查看和切换当前系统的拥塞控制算法:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 查看当前使用的拥塞控制算法
sysctl net.ipv4.tcp_congestion_control

# 查看内核支持的可用算法
sysctl net.ipv4.tcp_available_congestion_control

# 临时切换到 BBR(重启后失效)
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

# 永久生效:写入 sysctl 配置文件
echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.conf

# 检查内核版本(BBR 需要 Linux 内核 ≥ 4.9)
uname -r

输出示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看当前算法
$ sysctl net.ipv4.tcp_congestion_control
net.ipv4.tcp_congestion_control = cubic

# 查看可用算法
$ sysctl net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_available_congestion_control = reno cubic bbr

# 检查内核版本(必须 ≥ 4.9 才能使用 BBR)
$ uname -r
5.15.0-91-generic

如果输出中没有 bbr,说明内核没有加载 BBR 模块。可以手动加载:

bash
1
2
3
4
5
# 加载 BBR 模块
sudo modprobe tcp_bbr

# 确认模块已加载
lsmod | grep tcp_bbr

需要注意的是,拥塞控制算法的更换是系统全局的——所有新建的 TCP 连接都会使用新算法。已经建立的连接会继续使用创建时的算法,不受切换影响。

近年来随着 eBPF 技术的发展,Linux 还支持通过 BPF(BPF_PROG_TYPE_SOCK_OPS)实现用户自定义的拥塞控制算法,为拥塞控制的研究和部署提供了新的灵活性。

性能对比

有损链路吞吐量对比

不同拥塞控制算法在有损链路下的表现差异巨大。以下是在相同网络条件下(100ms RTT,100Mbps 带宽)的吞吐量对比数据:

丢包率RenoCUBICBBR
0%100%100%100%
0.1%~50%~85%~99%
1%~10%~30%~95%
3%~3%~12%~88%
5%~1%~5%~80%
10%~0.5%~2%~60%

从上表可以清晰看出:

  • 在 0.1% 低丢包率下,CUBIC 还能保持约 85% 的吞吐量,Reno 已经损失了一半带宽。
  • 在 1% 丢包率下,CUBIC 跌至约 30%,而 BBR 仍能保持 95% 以上——这正是无线网络、蜂窝网络常见的丢包范围。
  • 在 5% 丢包率下,Reno 和 CUBIC 基本不可用,而 BBR 仍能维持约 80% 的吞吐量。

这也解释了为什么一些网络应用(如 P2P 传输、视频流媒体)在无线网络环境中传输性能不佳——不仅仅是应用层协议的问题,底层的 TCP 拥塞控制算法同样关键。

算法特性对比

不同的拥塞控制算法在拥塞信号、适用场景和设计哲学方面各有特点:

算法年份类型核心拥塞信号适用场景
Tahoe1988基于丢包重复 ACK / 超时历史参考
Reno1990基于丢包重复 ACK低带宽、低延迟
Vegas1994基于延迟RTT 变化低延迟网络
NewReno1996基于丢包部分 ACK中等丢包链路
Westwood+2002带宽估计ACK 速率 + 丢包无线网络
BIC2004基于丢包重复 ACK高 BDP 网络
Hybla2004基于丢包RTT 归一化卫星链路
CUBIC2005基于丢包重复 ACK(时间驱动)Linux 默认 / 通用
DCTCP2010混合ECN 标记比例数据中心
BBR v32016基于模型BtlBw + RTprop高吞吐 / 无线链路
PCC2016性能驱动效用函数通用 / 复杂链路
Copa2018基于延迟排队延迟通用 / 低延迟

从算法类型和适用场景的多样性可以看出,不存在放之四海而皆准的"最佳"拥塞控制算法——正确的选择取决于具体的网络环境、应用需求和部署约束。

参考资料

  • Jacobson, V. (1988). Congestion avoidance and control. SIGCOMM ‘88.
  • Brakmo, L. S., & Peterson, L. L. (1995). TCP Vegas: End to end congestion avoidance on a global Internet. IEEE Journal on Selected Areas in Communications, 13(8).
  • Floyd, S., & Henderson, T. (1999). The NewReno modification to TCP’s fast recovery algorithm. RFC 2582.
  • Mascolo, S., et al. (2001). TCP Westwood: Bandwidth estimation for enhanced transport over wireless links. MobiCom ‘01.
  • Xu, L., Harfoush, K., & Rhee, I. (2004). Binary increase congestion control (BIC) for fast long-distance networks. INFOCOM 2004.
  • Caini, C., & Firrincieli, R. (2004). TCP Hybla: a TCP enhancement for heterogeneous networks. International Journal of Satellite Communications and Networking, 22(5).
  • Ha, S., Rhee, I., & Xu, L. (2008). CUBIC: a new TCP-friendly high-speed TCP variant. ACM SIGOPS Operating Systems Review, 42(5).
  • Alizadeh, M., et al. (2010). Data Center TCP (DCTCP). SIGCOMM ‘10.
  • Cardwell, N., et al. (2016). BBR: Congestion-based congestion control. ACM Queue, 14(5).
  • Dong, M., et al. (2015). PCC: Re-architecting congestion control for consistent high performance. NSDI ‘15.
  • Arun, V., & Balakrishnan, H. (2018). Copa: Practical delay-based congestion control for the internet. NSDI ‘18.
  • Cardwell, N., et al. (2022). BBR Congestion Control (IETF Draft). https://datatracker.ietf.org/doc/draft-cardwell-iccrg-bbr-congestion-control/