/ Google

对 Google TCP BBR 的浅薄认识

关于 Google 发布的新的 TCP 拥塞控制算法 BBR (Bottleneck Bandwidth and RTT) 的一些记录,仍然在学习中,难免有误解。之后会持续修正和完善。

网络链路上的包比较少时,道路很通畅,这个阶段,对于一个 TCP 连接来说,它的速度由这个连接两端之间的距离决定,也可以说是由 RTT 决定。当发包速率变大,把道路基本上填满了之后,这个阶段,带宽的大小决定了这个连接的速度,这时两端之间可能就会有包要排队,延迟时间除了 RTT 还有排队时间。

BBR 目的是要尽量跑满带宽,并且尽量不要有排队的情况。

cwnd 是普通的拥塞控制算法里最终要求得的一个值,用来控制发包速率。BBR 也要求到这个值,但是它不是最主要的控制发包速率的变量,主要的变量是 pacing_rate

这两个变量都由探测到的带宽值和 RTT 值得到,整个过程都围绕着这两个值。在 BBR 算法中,有四种状态,几种状态可能会有如下的转换:

            |
            V
   +---> STARTUP  ----+
   |        |         |
   |        V         |
   |      DRAIN   ----+
   |        |         |
   |        V         |
   +---> PROBE_BW ----+
   |      ^    |      |
   |      |    |      |
   |      +----+      |
   |                  |
   +---- PROBE_RTT <--+

另外还有一个重要变量,是在不同状态,不同阶段取的不同增益系数,比如有时需要多发包探测到最大瓶颈带宽,有时需要把发包量降下来探测较为准确的 RTT。

STARTUP 类似与普通拥塞控制里的慢启动,增益系数是 2ln2,每一个来回都以这个系数增大发包速率,估测到带宽满了就进入 DRAIN 状态 —— 连续三个来回,测得的最大瓶颈带宽没有比上一轮增大 25% 以上,就算做带宽满了。

进入 DRAIN 状态,增益系数小于 1,也就降速了。一个包来回,把 STARTUP 状态中产生的队列“抽干”,怎么样测算到队列空了?发出去还没有 ACK 的包量 inflight,与 BDP (带宽延迟积)进行比较,inflight < BDP 说明空了,道路不那么满了,如果 inflght > BDP 说明还不能到下一个状态,继续 DRAIN。

PROBEBW 是稳定状态,这时已经测出来一个最大瓶颈带宽,而且尽量不会产生排队现象。之后的每个来回,在 PROBEBW 状态循环(除非要进入下面提到的 PROBERTT 状态),轮询下面这些增益系数,5/4, 3/4, 1, 1, 1, 1, 1, 1,如此,最大瓶颈带宽就会在其停止增长的地方上下徘徊。大部分时间都应该处于 PROBEBW 状态。

前面三种状态,都可能进入 PROBERTT 状态。超过十秒没有估测到更小的 RTT 值,这时进入 PROBERTT 状态,把发包量降低,空出道路来比较准确得测一个 RTT 值,至少 200ms 或一个包的来回之后退出这个状态。检查带宽是否是满的,进入不同的状态:如果不满,进入 STARTUP 状态,如果满,进入 PROBEBW 状态。