拥塞窗口 · 在途数据别太多
除了控制发送速率,还要限制「已发出但还没被确认」的在途数据量——这是拥塞窗口。这一章读 goog_cc 的 congestion_window_pushback_controller,讲清在途数据为什么要有上限、超限时怎么「回压」减速,以及它和 pacing、码率控制如何配合防止缓冲区膨胀。
拥塞窗口 · 在途数据别太多
Pacing 控制“发多快”,但还有一个正交的约束:“已经发出去、但还没收到确认”的数据(in-flight)不能太多。 这个约束叫拥塞窗口(congestion window),由 goog_cc/congestion_window_pushback_controller.h 实现。它是 GoogCC 防止延迟失控的又一道闸。
在途数据:堆在网络里的量
“在途数据”= 你已经发出、但对端还没通过反馈确认收到的那些包的总量。 它反映“此刻有多少数据正堆在网络的缓冲区里”。哪怕发送速率看着合理,如果在途数据持续堆积(发得比确认回来的快),这些数据就在瓶颈路由器的缓冲区里排长队——这正是 bufferbloat(缓冲区膨胀) 的成因:缓冲区被塞满,每个包都要等前面一长串,延迟飙升。
拥塞窗口给在途数据设一个上限:一旦在途量逼近上限,就别再往里灌了,等确认回来、腾出空间再发。这和 TCP 的拥塞窗口 cwnd 是同一个思想——不光管“速率”,还管“总量”,双重保险地防止把网络缓冲区塞爆。
Pushback:超限就回压
WebRTC 的实现叫 CongestionWindowPushbackController——名字里的 pushback(回压) 点明了它的工作方式:
- 计算一个目标拥塞窗口(基于估计的带宽和 RTT:带宽 × RTT ≈ “填满这条路”所需的数据量)。
- 监控当前在途数据量。
- 在途量超过窗口 → 回压:主动压低实际发送码率(在 pacing 之上再踩一脚刹车),让发送慢下来,直到在途数据回落到窗口内。
三道闸,层层设防
到这里,GoogCC 控制发送的手段已经有三层,各管一个维度:
三者协同:码率估计定“目标速度”,pacing 保证“匀速吐出”,拥塞窗口兜底“总量不超”。多重、正交的约束,让 GoogCC 在各种刁钻网络下都能稳住延迟——这种“不把鸡蛋放一个篮子”的冗余设计,是实时系统鲁棒性的来源。
小结与下一章
拥塞窗口限制在途(已发未确认)数据量,防 bufferbloat(缓冲区膨胀导致延迟飙升)。CongestionWindowPushbackController 算一个目标窗口(≈带宽 × RTT),在途超限就回压——在 pacing 之上再踩刹车,优先保低延迟。它是码率估计、pacing 之外的第三道闸,三者正交设防。
估计、探测、pacing、窗口都齐了。最后一章把它们收成一个闭环,并看估出的码率怎么变成编码器的指令。👉 码率控制与闭环。
参考资料
- [1] libwebrtc 源码.
modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h。 - [2] 关联 bufferbloat 与 TCP cwnd —— 在途数据限制的共同思想。
- [3] IETF「GoogCC」draft。