TCP 拥塞控制:从慢启动到 BBR
互联网上的绝大多数流量由 TCP 承载。TCP 不仅要保证数据可靠、有序地到达,还承担着一项容易被忽视的职责:避免把网络压垮。发送方无法直接看到网络内部的状态,路由器的队列是否已满、链路是否拥塞,它都只能间接推测。拥塞控制算法就是在这种信息不完备的条件下,决定"此刻应该发多快"的一套机制。
本文从拥塞控制的必要性讲起,依次介绍经典的慢启动与拥塞避免、快速重传与快速恢复、CUBIC 算法,以及基于带宽与时延建模的 BBR 算法。
一、为什么需要拥塞控制
流量控制与拥塞控制的区别
TCP 中有两个容易混淆的概念。
流量控制关注的是接收方:接收方的缓冲区有限,发送方不能发得比接收方处理得更快。接收方通过 TCP 头部中的接收窗口字段告知发送方自己还能接收多少数据。
拥塞控制关注的是网络:即使接收方处理能力充足,中间的路由器和链路也可能不堪重负。发送方需要自行估计网络的承载能力,并维护一个拥塞窗口(cwnd)。
发送方实际能够发出但尚未确认的数据量,取接收窗口与拥塞窗口中的较小值。
拥塞崩溃
如果没有拥塞控制,当网络负载超过容量时,路由器队列溢出导致丢包,发送方检测到丢包后重传,重传又进一步加重拥塞,形成恶性循环。最终网络中充斥着大量重传包,有效吞吐量急剧下降,这种现象称为拥塞崩溃。
20 世纪 80 年代中期,早期互联网就曾多次发生拥塞崩溃,部分链路的有效吞吐量下降到原来的千分之一。此后 Van Jacobson 等人提出了一系列拥塞控制机制,奠定了现代 TCP 拥塞控制的基础。
二、经典算法的四个阶段
经典的 TCP 拥塞控制(以 Reno 为代表)可以分为四个组成部分:慢启动、拥塞避免、快速重传和快速恢复。
1. 慢启动
连接刚建立时,发送方对网络容量一无所知。慢启动的策略是:从一个较小的拥塞窗口开始(现代实现通常为 10 个最大报文段),每收到一个确认,拥塞窗口增加一个报文段。
由于一个往返时间(RTT)内发出的每个报文段都会带回一个确认,这意味着拥塞窗口每个 RTT 翻倍,呈指数增长。名字虽然叫"慢启动",实际增长速度相当快,"慢"是相对于连接一开始就以最大速率发送而言的。
慢启动持续到以下任一情况发生:
- 拥塞窗口达到慢启动阈值(ssthresh),转入拥塞避免阶段;
- 检测到丢包,进入相应的丢包处理流程。
2. 拥塞避免
当拥塞窗口达到慢启动阈值后,说明已经接近此前探测到的网络容量,继续指数增长风险较大。此时转入拥塞避免阶段:每个 RTT,拥塞窗口只增加一个报文段,呈线性增长。
线性增长与发生拥塞时的窗口减半相结合,构成了著名的 AIMD(加性增、乘性减)原则。理论分析表明,当多条连接共享同一瓶颈链路时,AIMD 能够使它们的带宽分配逐渐收敛到公平状态。
3. 超时重传
如果发送方在重传超时时间(RTO)内没有收到某个报文段的确认,就认为该报文段丢失。超时通常意味着网络发生了较严重的拥塞,此时的处理最为保守:
- 将慢启动阈值设为当前拥塞窗口的一半;
- 将拥塞窗口重置为初始值;
- 重新进入慢启动。
4. 快速重传与快速恢复
等待超时代价很高,RTO 往往远大于 RTT。实际上,如果只是个别报文段丢失,而后续报文段正常到达,接收方会对每个乱序到达的报文段重复确认最后一个按序收到的位置。
快速重传规定:当发送方收到三个重复确认时,不必等待超时,立即重传被认为丢失的报文段。
快速恢复则认为:既然还能收到重复确认,说明网络仍在传递数据,拥塞并不严重,没必要退回到慢启动。因此:
- 将慢启动阈值设为当前拥塞窗口的一半;
- 将拥塞窗口设为新的阈值(再加上少量补偿);
- 直接进入拥塞避免阶段。
这样拥塞窗口的变化曲线呈现出典型的"锯齿状":线性上升,遇到丢包减半,再线性上升。
三、经典算法在高速网络中的困境
Reno 的设计年代,网络带宽以 Kbps 或 Mbps 计。随着光纤网络普及,出现了大量高带宽、长时延的链路,例如跨洲数据中心之间的专线。这类链路的带宽时延积(BDP,即带宽乘以 RTT)非常大,需要极大的拥塞窗口才能填满。
以一条 10 Gbps、RTT 为 100 毫秒的链路为例,BDP 约为 125 MB,折合约八万多个报文段。在拥塞避免阶段,Reno 每个 RTT 只增加一个报文段。一次丢包使窗口减半后,需要四万多个 RTT,也就是一个多小时,才能恢复到满速。而在这么长的时间内,几乎不可能不发生任何丢包。结果是链路长期处于利用率不足的状态。
此外,Reno 的增长速度与 RTT 相关:RTT 越短的连接,窗口增长越快,在与长 RTT 连接竞争时占据优势,导致公平性问题。
四、CUBIC:用三次函数调整窗口
为了解决上述问题,研究者提出了多种改进算法,其中 CUBIC 应用最广,长期作为多个主流操作系统的默认拥塞控制算法。
核心思想
CUBIC 的窗口增长不再依赖于收到的确认数量,而是依赖于距离上次拥塞事件经过的时间。设上次发生丢包时的窗口大小为 W_max,CUBIC 用一个三次函数描述之后的窗口变化,其形状具有以下特点:
- 丢包后,快速增长:窗口远低于 W_max 时,增长较快,迅速恢复吞吐;
- 接近 W_max,放缓增长:在上次发生拥塞的位置附近,增长变得平缓,谨慎试探,避免再次引发拥塞;
- 越过 W_max,再次加速:如果在 W_max 附近没有发生丢包,说明网络容量可能已经增加,窗口加速增长,探测新的上限。
这条曲线呈现出先凹后凸的形状,恰好是三次函数的特征,这也是算法名称的由来。
优势
- RTT 公平性:窗口增长只与时间相关,不同 RTT 的连接在相同时间内增长幅度相近;
- 高带宽适应性:能够较快地填满大 BDP 链路;
- 兼容性:在低带宽或短 RTT 网络中,CUBIC 会退化为接近 Reno 的行为,与传统连接和平共处。
五、基于丢包的算法的根本问题
无论 Reno 还是 CUBIC,都属于基于丢包的拥塞控制:把丢包视为拥塞信号,没有丢包就持续增大窗口。这一设计在当今的网络环境中暴露出两个根本性问题。
1. 缓冲区膨胀
现代路由器和交换机往往配备了很大的缓冲区。基于丢包的算法会不断增大发送速率,直到缓冲区被填满、开始丢包为止。在缓冲区被填满的过程中,吞吐量并没有提升,因为瓶颈链路早已满载,但排队时延不断增加。
这种现象称为缓冲区膨胀(Bufferbloat)。它导致网络时延成倍上升,对视频通话、在线游戏等对时延敏感的应用影响尤其明显。
2. 丢包不等于拥塞
在无线网络、卫星链路等场景中,丢包往往由信号干扰、误码等原因导致,与拥塞无关。基于丢包的算法会把这类随机丢包误判为拥塞,不必要地降低发送速率。在丢包率稍高的链路上,吞吐量可能远低于实际带宽。
六、BBR:对网络建模
2016 年,Google 提出了 BBR(Bottleneck Bandwidth and Round-trip propagation time)算法。它不再把丢包作为拥塞的主要信号,而是主动测量并建模网络路径的两个关键参数。
最优工作点
一条网络路径可以用两个参数刻画:
- 瓶颈带宽(BtlBw):路径上最窄链路的传输速率;
- 往返传播时延(RTprop):在没有任何排队的情况下,数据往返一次所需的时间。
两者的乘积即为路径的 BDP。理论上,当在途数据量恰好等于 BDP 时,瓶颈链路被充分利用,同时路由器中没有排队,吞吐量最大、时延最小。这就是拥塞控制的最优工作点。
基于丢包的算法工作在缓冲区即将溢出的位置,远离最优点;BBR 的目标则是尽量贴近这个最优点运行。
测量的难点
BtlBw 和 RTprop 无法同时精确测量:
- 要测出最大带宽,需要发送足够多的数据使瓶颈链路满载,这时往往已经产生排队,测得的 RTT 偏大;
- 要测出最小 RTT,需要链路中没有排队,这时发送量较少,测不出最大带宽。
BBR 的解决办法是分时测量:在一个滑动时间窗口内,取观测到的最大交付速率作为 BtlBw 的估计,取观测到的最小 RTT 作为 RTprop 的估计,并通过周期性的主动探测来更新这两个值。
四个状态
BBR 的运行分为四个状态:
- 启动(Startup):类似慢启动,以指数方式提高发送速率,快速探测瓶颈带宽。当连续几轮交付速率不再明显增长时,认为已达到瓶颈带宽。
- 排空(Drain):启动阶段不可避免地在瓶颈处积累了排队,这一阶段短暂降低发送速率,把多余的排队排空。
- 带宽探测(ProbeBW):稳定运行的主要阶段。发送速率以瓶颈带宽估计值为中心周期性波动:短暂提高速率试探是否有更多可用带宽,随后降低速率排空可能产生的排队。
- 时延探测(ProbeRTT):如果较长时间内没有观测到更小的 RTT,就短暂将在途数据量降到很低,使路径上的排队清空,从而测得准确的传播时延。
发送节奏控制
BBR 的另一个特点是依赖节奏控制(Pacing):数据不是按窗口一次性突发发出,而是按照估计的瓶颈带宽均匀地间隔发送。这可以减少突发流量对瓶颈缓冲区的冲击。
效果与争议
在高丢包、深缓冲区的链路上,BBR 相比 CUBIC 往往能显著提高吞吐量并降低时延,这使它在长距离传输、视频分发等场景中得到广泛应用。
但 BBR 也存在一些问题。第一代 BBR 基本忽略丢包信号,在浅缓冲区网络中与 CUBIC 竞争时,可能占用过多带宽,导致公平性问题,同时引起较高的丢包率。后续的 BBRv2 和 BBRv3 引入了对丢包和显式拥塞通知(ECN)的响应,在保持低时延优势的同时,改善了与其他算法的共存能力。
七、算法对比
| 算法 | 拥塞信号 | 窗口/速率调整方式 | 优势 | 局限 |
|---|---|---|---|---|
| Reno | 丢包 | AIMD,线性增长、丢包减半 | 简单、公平性理论成熟 | 高 BDP 链路利用率低 |
| CUBIC | 丢包 | 基于时间的三次函数 | 适应高带宽、RTT 公平性好 | 导致缓冲区膨胀,误判随机丢包 |
| BBR | 带宽与时延模型 | 按估计带宽节奏发送 | 高吞吐、低排队时延,抗随机丢包 | 早期版本公平性存在争议 |
八、工程实践中的考量
根据场景选择算法。 数据中心内部网络 RTT 极短、丢包极少,许多系统会使用专门的数据中心拥塞控制算法;面向公网的服务器,尤其是长距离、弱网环境下的视频或文件分发,BBR 往往有明显收益;通用场景下 CUBIC 仍是稳妥的默认选择。
拥塞控制只在发送端生效。 拥塞控制算法运行在发送方,切换算法只需调整服务器端配置,客户端无需任何改动。对于下行流量为主的服务,这一特性使得优化成本很低。
配合队列管理机制。 缓冲区膨胀不能只靠端到端的算法解决。路由器侧的主动队列管理机制,例如 CoDel、FQ-CoDel 等,能够在排队时延过高时主动丢包或标记,与端侧算法配合,才能更好地控制时延。
关注尾部指标。 评估拥塞控制效果时,平均吞吐量只是一个方面,时延的分布、重传率、多流共存时的公平性同样重要。
注意新协议的变化。 基于 UDP 的新一代传输协议将拥塞控制从操作系统内核移到了用户态,应用可以更灵活地选择和迭代算法,这也使得拥塞控制算法的部署和实验变得更加容易。
结语
拥塞控制的本质,是在无法直接观测网络内部状态的条件下,通过有限的反馈信号推断网络容量,并在充分利用带宽与避免拥塞之间取得平衡。
从 Reno 的 AIMD,到 CUBIC 的三次函数,再到 BBR 的路径建模,拥塞控制算法的演进反映了网络环境本身的变化:带宽越来越高、缓冲区越来越深、无线链路越来越普遍。用来判断拥塞的信号,也从单一的丢包,逐渐扩展到带宽、时延和显式通知。可以预见,随着网络形态继续演变,这一领域仍会不断出现新的方案。
- 点赞
- 收藏
- 关注作者
评论(0)