4. 端到端拥塞控制:BBR算法、CUBIC算法、Vegas算法
端到端拥塞控制,说白了就是发送端自己判断网络是不是堵了,然后决定是踩油门还是踩刹车。我这些年调过不少TCP栈,见过最典型的三种算法就是BBR、CUBIC和Vegas。它们思路完全不同,适用场景也各有千秋。今天咱们就掰开揉碎了聊聊。
4.1 传统算法的困境:丢包就是信号?
在讲具体算法之前,我想先说说一个老观念——「丢包等于拥塞」。这个想法在早期网络里是对的,但现在呢?你想想看,无线网络、数据中心、长肥网络(LFN)里,丢包可能只是因为信号干扰或者缓冲区溢出,跟真正的链路拥塞没啥关系。
我遇到过好几次这样的坑:某次在数据中心调优,明明链路带宽还有富余,但CUBIC一检测到丢包就猛降窗口,结果吞吐量直接腰斩。后来我才意识到,问题出在交换机缓冲区太小,微突发就把包丢了。嗯,这里要注意,丢包≠拥塞,这个认知是理解BBR和Vegas的关键。
4.2 CUBIC算法:二进制的拥塞窗口
CUBIC是目前Linux默认的拥塞控制算法。它的核心思路很简单:窗口增长函数是一个三次函数(立方函数),所以叫CUBIC。
具体来说,CUBIC维护一个参数 W_max,表示上次丢包时的窗口大小。丢包发生后,窗口降到 0.7 * W_max,然后按照以下公式增长:
W(t) = C * (t - K)^3 + W_max
其中 t 是距离上次丢包的时间,K = (W_max * (1 - β) / C)^(1/3),β 是乘性减窗因子(通常0.3),C 是常数。
这个公式有什么好处?我举个例子:
- 窗口较小时:三次函数增长缓慢,避免频繁丢包
- 窗口接近W_max时:增长变缓,探测瓶颈带宽
- 窗口超过W_max后:增长加速,快速抢占带宽
我个人习惯把CUBIC比作「二进制搜索」——它在丢包点附近反复试探,找到当前网络的容量上限。但问题也在这里:它完全依赖丢包作为拥塞信号。在高速网络里,丢包前可能已经排队很久了,延迟早就飙升了。
4.3 Vegas算法:基于延迟的拥塞控制
Vegas是另一种思路——它不看丢包,而是看RTT(往返时延)的变化。为什么?因为网络一旦开始排队,RTT就会增加。Vegas认为,RTT增加才是拥塞的早期信号。
Vegas维护两个关键参数:
- BaseRTT:测量到的最小RTT,代表无拥塞时的延迟
- Expected Throughput:窗口大小 / BaseRTT,即理论最大吞吐
- Actual Throughput:窗口大小 / 当前RTT,即实际吞吐
然后计算差值:
diff = (Expected - Actual) * BaseRTT
这个 diff 代表当前网络中排队的数据包数量。Vegas的策略是:
| diff 值 | 动作 |
|---|---|
| diff < α | 窗口加1(带宽还有余量) |
| α ≤ diff ≤ β | 窗口不变(刚好合适) |
| diff > β | 窗口减1(排队太多) |
α 和 β 通常取2和4。说白了,Vegas想让网络中排队的数据包控制在2到4个之间。这个思路很优雅——它避免了缓冲区膨胀(Bufferbloat)。
4.4 BBR算法:基于模型的拥塞控制
BBR(Bottleneck Bandwidth and Round-trip propagation time)是Google在2016年提出的。它不依赖丢包,也不直接依赖RTT变化,而是建立一个网络模型:
- 瓶颈带宽(BtlBw):链路能承载的最大发送速率
- 往返传播时间(RTprop):无拥塞时的最小RTT
BBR的核心公式是:
发送速率 = min(瓶颈带宽, 窗口大小 / RTprop)
BBR的工作流程分为四个阶段:
- 启动(Startup):指数增长,探测瓶颈带宽
- 排空(Drain):降低发送速率,排空队列
- 带宽探测(ProbeBW):周期性提高速率,检查带宽是否变化
- RTT探测(ProbeRTT):周期性降低速率,测量最小RTT
我画了一张流程图,帮你理解BBR的状态机:
BBR的厉害之处在于,它通过周期性探测来维持对网络状态的认知。在ProbeBW阶段,它会以1.25倍速率发送,然后降到0.75倍,通过观察RTT变化来判断带宽是否变化。
4.5 三种算法的对比
我整理了一张对比表,方便你快速理解:
| 特性 | CUBIC | Vegas | BBR |
|---|---|---|---|
| 拥塞信号 | 丢包 | RTT增加 | 带宽/RTT模型 |
| 缓冲区占用 | 高(容易填满) | 低(控制在α~β) | 低(主动排空) |
| 公平性 | 好(与标准TCP兼容) | 较差(容易被CUBIC抢占) | 中等(需要多流共存调优) |
| 高速网络 | 一般(丢包恢复慢) | 差(RTT测量不准) | 优秀(主动探测) |
| 无线网络 | 差(误判丢包) | 中等(受RTT抖动影响) | 好(区分拥塞和丢包) |
| 部署难度 | 低(默认算法) | 低(内核支持) | 中(需内核≥4.9) |
4.6 实际选型建议
说了这么多,到底该用哪个?我个人习惯这样选:
- 通用互联网服务:用CUBIC。兼容性最好,大部分场景够用。
- 延迟敏感应用:用Vegas或BBR。比如视频会议、在线游戏,Vegas的延迟控制很稳。
- 数据中心/高速链路:用BBR。我曾在10Gbps链路上测试,BBR比CUBIC吞吐量高30%以上。
- 无线/移动网络:用BBR。它能区分无线丢包和拥塞丢包,不会乱降速。
4.7 小结
三种算法代表了三种不同的拥塞控制哲学:CUBIC相信丢包,Vegas相信延迟,BBR相信模型。没有的好坏,关键看你的网络环境和业务需求。
最后说一句:调拥塞控制算法,一定要结合你的实际流量特征。别光看理论,拿真实数据跑一跑,你会有更深的体会。
sysctl net.ipv4.tcp_congestion_control 查看当前算法,用 modprobe tcp_bbr 加载BBR模块。切换算法后记得用 ss -ti 观察每个连接的拥塞状态。
可可精品资料库