Stanford CS144 学习笔记 (四):网络拥塞控制与 AIMD 算法
导语在上一单元中我们学习了“流量控制 (Flow Control)”它解决的是接收方处理不过来的问题。但在真实的互联网中如果所有人都全速发包中间的路由器处理不过来怎么办这就会导致灾难性的“网络崩溃”。本单元我们将探究 TCP 是如何凭借天才般的“拥塞控制 (Congestion Control)”机制拯救互联网于水火之中的。1. Congestion - Basic Ideas (网络拥塞的本质)控制拥塞的核心目的是防止整个网络因为过载而陷入崩溃。1.1 So, what is it? (什么是拥塞)拥塞产生的原因非常简单需求 容量。具体表现在不同的时间尺度上微观 (Microscopic)两个数据包在路由器端口同时碰撞。中观 (Macroscopic)多条数据流 (Flows) 瞬间耗尽了某条链路的物理带宽。宏观 (Systemic)晚高峰期间海量用户同时挤入网络类似春运的高速公路。恶性正反馈当路由器发生拥塞开始丢包时如果不加控制发送方会因为超时而重传更多的数据包导致原本就拥堵的网络雪上加霜最终吞吐量降为零这就是“网络崩溃 (Congestion Collapse)”。1.2 Congestion is unavoidable (拥塞是不可避免的)为什么不把路由器的 Buffer 做得无限大如果 Buffer 极大确实不会丢包了但数据包会在里面排队等上好几秒Bufferbloat缓冲区膨胀导致端到端延迟高得离谱。这对网络利用率和实时应用来说是一场灾难。丢包是好事还是坏事无意义的丢包是对上游网络资源的浪费但适度的丢包其实是网络在向终端发出“我快撑不住了”的警告信号。1.3 Fairness and Throughput (公平与吞吐量的博弈)网络设计者面临一个两难境地是追求绝对的总吞吐量最大化还是追求每个用户的绝对公平Max-min Fairness (最大最小公平性)这是互联网普遍认可的公平原则。核心思想是“劫富济贫”——在分配资源时优先满足需求最小最吃亏的流如果还有剩余再平均分配给需求更大的流。坚决避免少数霸道流量挤占所有资源。2. Congestion - Basic Approaches (应对拥塞的基础策略)如何把网络拥塞的情况告诉发送方有两种截然不同的流派2.1 Network-based (基于网络核心的策略)让网络中间的路由器主动发声。机制当路由器快满时主动向终端发送 Signal信号告知正在拥堵。ECN (Explicit Congestion Notification, 显式拥塞通知)路由器会在处理数据包时在 IP 头部打上拥塞标记。这个标记到达目标主机后目标主机会借助返回的 ACK 报文“搭便车”把拥塞警告带回给源主机。2.2 End-host based (基于终端主机的策略)路由器什么都不用管全靠网络边缘的终端主机自己去猜TCP Congestion ControlTCP 采用的就是这种策略。它把网络当成一个黑盒。探测机制通过维护一个名为拥塞窗口 (Congestion Window, cwnd)的变量结合滑动窗口策略利用 RTT (往返时间) 和是否丢包来动态推测网络的拥堵程度。2.3 AIMD (加性增乘性减)TCP 拥塞控制的核心算法。这是一种“慢慢增加快速减少”的试探策略。Additive Increase (加性增加)如果没有发生拥塞发送速度“一点一点”地缓慢增加。Multiplicative Decrease (乘性减少)一旦检测到拥塞丢包发送速度“断崖式”砍半。视觉表现这导致 TCP 的发送窗口在时间轴上呈现出经典的“Sawtooth” (锯齿波)形状。3 4. Congestion - AIMD 动态表现TCP 不会刻意避免丢包相反“丢包”正是 AIMD 用来寻找网络容量上限的探测雷达。数学逻辑 (Single Multiple flows)收到 ACK 时 (if received)W - W 1/W。(注意味着每收到一个确认窗口增加1/W当收到一整窗W个确认时窗口刚好增加1。这保证了每经过一个 RTT窗口大小线性 1)发生丢包时 (if dropped)W - W / 2。(注立刻将窗口砍半给网络极大的喘息空间)吞吐量公式在 AIMD 算法下一条流的长期平均吞吐量近似为Throughput ∝ W / RTT。在多条流共享链路时AIMD 的这种锯齿状调整最终会在数学上奇迹般地收敛到一条代表“绝对公平”的均衡线上。5. TCP Congestion Control Ⅰ (TCP 拥塞控制演进史)TCP 内部维护了几个关键变量来控制速度cwnd(拥塞窗口) 和ssthresh(慢启动阈值)。5.1 TCP Three Questions (TCP 的哲学三问)设计任何可靠协议都要回答什么时候发送新数据 (由 cwnd 和滑动窗口决定)什么时候重传数据 (由超时或三次重复 ACK 决定)什么时候确认数据 (累计确认机制)5.2 状态流转 (State Transitions)TCP 在运行中主要在以下状态中切换Slow Start (慢启动)名字叫“慢”其实是指数爆炸初始窗口很小如 1 个包但每收到一个 ACK窗口加 1。这意味着每个 RTT 窗口翻倍 (1→2→4→81 \to 2 \to 4 \to 81→2→4→8)。目的以极快的速度探测出当前网络的可用容量直到触碰阈值 (ssthresh)。Congestion Avoidance (拥塞避免)当cwnd ssthresh时进入此阶段。退化为 AIMD 的线性增长模式每个 RTT 窗口仅仅加 1谨慎试探拥塞点。6. TCP Congestion Control Ⅱ (超时与时钟机制)6.1 RTT Estimation (RTT 估计与超时陷阱)为什么难现实网络中 RTT 的波动极大。如果超时时间设得太长丢包后系统迟迟不重传浪费时间设得太短又会导致把正常延迟误判为丢包引发频繁的无效重传加剧拥堵。Self-Clocking (自时钟机制)TCP 巧妙地利用接收方返回的 ACK 作为系统运转的“心脏起搏器”。收到一个 ACK就代表网络腾出了一个包的空间发送方就可以安全地注入一个新包。6.2 Pre-Tahoe 到 Tahoe 的飞跃早期 TCP (Pre-Tahoe)完全依赖定时器超时。只要超时就把窗口重置为 1效率极其低下。TCP Tahoe 的两大创举Fast Retransmit (快速重传)如果发送方连续收到3 个重复的 ACK说明后续的包到了但中间某个包丢了。此时不等超时立刻重传丢失的包但是Tahoe 依然比较原始无论是超时还是 3 次重复 ACK它都会把ssthresh设为当前窗口的一半然后极其保守地把cwnd降为 1重新开始慢启动。7. TCP Congestion Control Ⅲ (Reno 与 NewReno)为了解决 Tahoe 每次丢包都要从 1 重新开始的低效问题专家们对 TCP 进行了迭代。7.1 TCP Reno (引入快速恢复)核心改进丢包后不再傻傻地回到 0 点Fast Recovery (快速恢复)如果是超时丢包Reno 和 Tahoe 一样回到 1。但如果是收到3 个重复 ACK触发的丢包Reno 认为“既然还能收到 ACK说明网络还有流通能力”。此时Reno 直接把cwnd减半跳过慢启动直接从半山腰进入拥塞避免阶段。极大提高了网络吞吐量。7.2 TCP NewReno (终极优化)Reno 的致命弱点如果一个发送窗口内有多个包同时丢失Reno 的快速恢复机制会彻底混乱导致多次将窗口减半最终饿死自己。NewReno 的优化优化了快速恢复机制的逻辑引入了“部分确认 (Partial ACK)”的概念。它能够敏锐地识别出一个窗口内的多次丢包并在一次恢复周期内高效处理避免了盲目减半。7.3 对比总结表版本关键改进收到 3 个重复 ACK 的反应效率评价Tahoe引入快速重传cwnd 1重新慢启动丢包后恢复极慢Reno引入快速恢复cwnd cwnd / 2拥塞避免恢复快但怕单窗多丢包NewReno优化多重丢包cwnd cwnd / 2智能恢复更复杂更高效8. TCP Congestion Control Ⅳ (拥塞控制的终极目标)回顾 AIMD它实际上在两者之间实现了完美的平衡Service Provider (运营商/网络层)希望Maximize link utilization(链路利用率最大化别让线路空着)。User (终端用户)希望Fair share(公平共享谁也别独占带宽)。通过分布式的 AIMD 探测TCP 成功避免了 Congestion Collapse支撑起了今天庞大而繁荣的互联网。9. Reading an RFC (阅读互联网的“宪法”)RFC (Request for Comments) 是 IETF 发布的技术规范文档。互联网上所有的规则都在这里面。History从 1969 年开始发布记录了互联网从无到有的史诗。Necessities (为什么要读)写底层代码如开发服务器、抓包工具时的最高权威参考。网络工程师排查疑难杂症的终极词典。Something Common (经典 RFC 必知)TCP 协议RFC 793HTTP 协议RFC 7230DNS 协议RFC 1035(注阅读 RFC 不需要从头读到尾学会利用目录找到你需要的 Protocol Header 结构和状态机定义即可。)