2.6 网络拥塞控制原理与实践 你可能听说过与 TCP/IP 协议相关的术语,如 Cubic、Tahoe、Vegas、Reno、Westwood 以及近年来流行的 BBR 算法,这些都是网络传输层使用的拥塞控制算法。 拥塞控制算法直接影响网络吞吐(throughput)的效率。本节,我们分析拥塞控制的原理,回顾不同阶段互联网拥塞控制算法的设计,并深入探讨 BBR 算法如何在弱网环境下显著提升网络吞吐效率。 2.6.1 网络拥塞控制原理 网络吞吐效率与 RTT 和传输速率密切相关: RTT 越低,数据传输的延迟越短; 传输速率越高,网络在单位时间内处理的数据越多。 图 2-22 展示了这两者的变化逻辑及其对网络传输效率的影响。
你可能听说过与 TCP/IP 协议相关的术语,如 Cubic、Tahoe、Vegas、Reno、Westwood 以及近年来流行的 BBR 算法,这些都是网络传输层使用的拥塞控制算法。
拥塞控制算法直接影响网络吞吐(throughput)的效率。本节,我们分析拥塞控制的原理,回顾不同阶段互联网拥塞控制算法的设计,并深入探讨 BBR 算法如何在弱网环境下显著提升网络吞吐效率。
网络吞吐效率与 RTT 和传输速率密切相关:
图 2-22 展示了这两者的变化逻辑及其对网络传输效率的影响。
:::center
图 2-22 RTT 与传输速率变化对网络吞吐效率的影响
:::
首先,解释图中的一些术语,它们的含义如下:
受 RTT 和传输速率的影响,图 2-22 被分成了三个区间:
根据图 2-22,可以看出,拥塞的本质在于 inflight 数据量持续偏离 BDP 线向右扩展,而拥塞控制的关键在于调节 inflight 数据量保持在合适的区间内。显然,当 inflight 数据量位于应用受限区与带宽受限区的边界时,传输速率接近瓶颈带宽,且无丢包发生。
早期互联网的拥塞控制以丢包为控制条件,控制逻辑如图 2-21 所示。
发送方维护一个称拥塞窗口的状态变量 cwnd,其值取决于网络拥塞的程度和所采用的拥塞控制算法。当发送方开始发送数据时,进入慢启动(Slow Start)阶段,也就是慢慢增大拥塞控制窗口;当出现丢包时,进行拥塞避免(Congestion Avoiance)阶段,也就是减小拥塞控制窗口;当丢包不再出现时,再次进入慢启动阶段,如此一直反复。
:::center
图 2-21 早期以丢包为条件的拥塞控制
:::
以丢包为控制条件的机制适应了早期互联网的特征:低带宽和浅缓存队列。
随着移动互联网的快速发展,特别是图片和音视频应用的普及,网络负载大幅增加。与此同时,摩尔定律推动设备的性能不断提升和成本不断降低。当路由器、网关等设备的缓存队列增加,网络链路变得更长、更宽时,RTT 可能因缓存队列增大而增加,丢包则可能源于链路过长。网络变差,并不总是因链路拥塞所致。
因此,以丢包为控制条件的传统拥塞控制算法就不再适用了。
如果说早期的拥塞控制算法目的在于收敛,防止互联网服务发生“拥塞崩溃”。那么,BBR 的目标则是充分利用链路带宽和路由/网关设备的缓存队列,最大化网络效能。
最大化网络效能的前提是找到网络传输中的最优点,图 2-22 中的两个黑色圆圈即代表网络传输的最优点:
当网络传输处于最优点时:
然而,最小延迟与最大带宽互相矛盾,无法同时测量。如图 2-24 所示:测量最大带宽时,必须填满瓶颈链路,此时缓冲区被沾满,导致延迟增大;测量最小延迟时,需确保缓冲区为空,这又无法测得最大带宽。
:::center
图 2-24 无法同时得到 max BW 和 min RTT
:::
BBR 的解题思路是不再考虑丢包作为拥塞的判断条件,而是交替测量带宽和延迟。
BBR 通过观测一段时间内的最大带宽和最小延迟来估算发包速率。稳定控制发送速度的同时,尽可能充分榨干带宽:
BBR 的拥塞控制状态机是实现上述设计的核心基础。该状态机在任何时刻处于以下四种状态之一:启动(STARTUP)、排空(DRAIN)、带宽探测(PROBE_BW)和时延探测(PROBE_RTT)。这四种状态的含义以及转换关系如图 2-23 所示。
:::center
图 2-23 BBR 状态转移关系
:::
Linux 内核从 4.9 开始集成了 BBR 拥塞控制算法。此后,在绝大数的 Linux 发行版中,只要几个命令就能使用 BBR 提升网络传输效率。
$ sysctl net.ipv4.tcp_available_congestion_control net.ipv4.tcp_congestion_control = bbr cubic reno
上面返回的结果中,显示当前系统支持 bbr、cubic 和 reno 三种拥塞控制算法。
$ sysctl net.ipv4.tcp_congestion_control net.ipv4.tcp_congestion_control = cubic
绝大部分 Linux 系统默认的拥塞控制算法为 Cubic 算法。
$ echo net.ipv4.tcp_congestion_control=bbr >> /etc/sysctl.conf && sysctl -p
网络拥塞控制是单向生效,也就是说作为下行方的服务端调整了,BBR 算法即可生效。
接下来,我们使用 tc 工具模拟弱网环境,使用网络性能测试工具 iperf3 测试弱网环境下不同的拥塞控制算法的表现。
首先,在服务端设置 eth0 网络接口上的流量丢包率为 1%、延迟为 25ms。
$ tc qdisc add dev eth0 root netem loss 1% latency 25ms
接着,在服务端使用 iperf3 开启测试服务,以服务端模式运行,设置监控时间2秒,并指定端口为 8080。
$ iperf -s -p 8080 -i 1
在客户端节点使用 iperf3 以客户端模式运行,请求 10.0.1.188 服务端的 8080 端口。
$ iperf3 -c 10.0.1.188 -p 8080
测试结果如表 2-3 所示。可以看出,BBR 在轻微丢包的网络环境下表现尤为出色。
:::center
表 2-3 不同网络环境下,各拥塞控制算法的网络吞吐表现 表数据来源
:::
| 服务端的拥塞控制算法 | 延迟 | 丢包率 | 网络吞吐表现 |
|---|---|---|---|
| Cubic | <1ms | 0% | 2.35Gb/s |
| Reno | <140ms | 0% | 195 Mb/s |
| Cubic | <140ms | 0% | 147 Mb/s |
| Westwood | <140ms | 0% | 344 Mb/s |
| BBR | <140ms | 0% | 340 Mb/s |
| Reno | <140ms | 1.5% | 1.13 Mb/s |
| Cubic | <140ms | 1.5% | 1.23 Mb/s |
| Westwood | <140ms | 1.5% | 2.46 Mb/s |
| BBR | <140ms | 1.5% | 160 Mb/s |
| Reno | <140ms | 3% | 0.65 Mb/s |
| Cubic | <140ms | 3% | 0.78 Mb/s |
| Westwood | <140ms | 3% | 0.97 Mb/s |
| BBR | <140ms | 3% | 132 Mb/s |