跳转至

流量控制与拥塞控制

两个名字相似、对象不同的问题

  • 流量控制保护接收端:接收应用读得慢,发送方不能把其缓存撑爆。
  • 拥塞控制保护网络:路径中的链路和路由器被许多流竞争,发送方不能无限注入分组。

接收端很快并不代表网络不拥塞;网络空闲也不代表接收应用来得及处理。因此两个机制都需要。

流量控制:接收窗口

TCP 接收方在 ACK 中通告接收窗口 rwnd,表示当前还能接收多少字节。发送方未确认的在途数据不能超过该窗口。

最小例子:接收缓存容量 64 KB,已有 48 KB 尚未被应用读取,则可通告约 16 KB 窗口。随着应用读取数据,接收方扩大窗口。若窗口降为 0,发送方暂停常规数据,并通过窗口探测避免“窗口更新报文丢失后双方永久等待”。

流量控制不能解决应用永远不读取的问题。此时连接可能长期占用内存,服务器仍需超时、并发限制和背压策略。

拥塞是怎样形成的

多个发送方同时把数据注入瓶颈链路,路由器先排队,队列满后丢包。若发送方把所有丢包都理解为“网络偶然损坏”并立刻猛烈重传,会制造更多负载,甚至发生拥塞崩溃。

端到端拥塞控制通过 ACK 到达节奏、丢包、时延或显式拥塞通知推断路径状态。核心矛盾是:不尝试提高速率就不知道可用容量,尝试过快又会伤害其他流和自己。

拥塞窗口与实际发送上限

发送方维护拥塞窗口 cwnd。粗略地说,可在途数据受两者较小值限制:

\[ W_{send}=\min(rwnd,cwnd). \]

rwnd 很小表示接收方是瓶颈,cwnd 很小表示发送方对网络容量的估计更谨慎。实际 TCP 还受发送缓存、应用供数速度和实现策略影响。

从慢启动到拥塞避免

连接开始时不知道路径容量。经典 TCP 使用慢启动:从较小窗口开始,每收到确认就允许更多数据,窗口按 RTT 近似指数增长。名字叫“慢”,其实增长很快;它相对于直接以线速发送更谨慎。

达到阈值或出现拥塞信号后进入拥塞避免,经典直觉是加性增大、乘性减小

没有明显拥塞:逐步增加窗口,探索剩余容量
出现拥塞信号:显著降低窗口,给队列和其他流让空间

这种 AIMD 行为能让长期竞争的相似流趋向较公平份额,但现实公平性会受 RTT、算法、并发连接数和路径差异影响。一个应用打开许多并行连接,可能获得比单连接应用更多份额。

丢包不是唯一信号

传统算法常把丢包视作拥塞信号;无线误码也可能丢包,误判会降低吞吐。现代算法可能结合时延、带宽估计或显式拥塞通知 ECN。不同目标之间存在权衡:

  • 激进探测可快速占满新容量,却可能增加队列和丢包。
  • 时延敏感算法努力保持短队列,但与激进丢包型流共存时可能吃亏。
  • 高吞吐算法适合大文件,不一定适合游戏和远程控制。

QUIC 也需要拥塞控制。运行在 UDP 之上并不意味着可以绕过网络公平与安全约束。

最小完整诊断例子

现象:下载速度高,但开始下载后 SSH 明显卡顿。

可能链路如下:大流把接入路由器缓冲区填满,小型 SSH 分组排在大量数据后面,形成缓冲膨胀。验证方法是下载前后持续测量 RTT;若吞吐保持而 RTT 从几十毫秒上升到数百毫秒,说明问题不只是“带宽不足”。可考虑智能队列管理、公平排队、限制大流速率或改善上行容量。

与应用背压的联系

传输层窗口是字节级背压,应用系统也需要业务级背压。例如消息消费者处理不过来时,应限制生产速率或缩短预取,而不是无限堆积内存。两者动机相同:让上游感知下游容量;但应用背压理解任务语义,TCP 只理解字节和缓存。

自测

接收方通告 1 MB 窗口,发送方为什么仍可能只能保持 64 KB 在途?

拥塞窗口可能只有 64 KB;实际发送上限受 rwndcwnd 的较小值约束。也可能是应用没有足够数据或发送缓存受限。