TCP BBR的startup bbr_high_gain为什么是2/ln2?

温州皮鞋厂老板上周就一直在问这个。正好昨天和今天早上有空,加上又在雨夜,就写一波。

温州皮鞋厂老板的问题如下:

慢启动:
init_cwnd×2n=cwnd

i

n

i

t

_

c

w

n

d

×

2

n

=

c

w

n

d


增长速率为
2n

2

n

求导=
n×2n1

n

×

2

n

1

. pacing_gain应该等于类似这个东西来算吧
怎么就
2ln2

2

l

n

2

其实一开始我也不知道,根本就没有注意过这个问题,能找到的资料也就是tcp_bbr.c中关于bbr_high_gain的注释:

/* We use a high_gain value of 2/ln(2) because it's the smallest pacing gain
 * that will allow a smoothly increasing pacing rate that will double each RTT
 * and send the same number of packets per RTT that an un-paced, slow-starting
 * Reno or CUBIC flow would:
 */
static const int bbr_high_gain  = BBR_UNIT * 2885 / 1000 + 1;

另外,BBR的paper:
https://queue.acm.org/detail.cfm?id=3022184
这里面也能找到一段论述:

To handle Internet link bandwidths spanning 12 orders of magnitude, Startup implements a binary search for BtlBw by using a gain of 2/ln2 to double the sending rate while delivery rate is increasing. This discovers BtlBw in log2BDP RTTs but creates up to 2BDP excess queue in the process.

除此之外,就再也找不到别的资料了。我自己也很好奇,也跟很多人进行了讨论,甚至包括BBR的作者之一Neal Cardwell,最终以我自己的理解,整理出了这篇文章,希望能帮同样有此疑问的人解惑。


在Startup阶段,BBR的bbr_high_gain同时作用于
PacingRate

P

a

c

i

n

g

R

a

t

e


Cwnd

C

w

n

d

两者,两者遵循同样的演化规律,即随着
RTT

R

T

T

轮数而指数级递增:


PacingRate=f1(rounds)=R0×2rounds

P

a

c

i

n

g

R

a

t

e

=

f

1

(

r

o

u

n

d

s

)

=

R

0

×

2

r

o

u

n

d

s



Cwnd=f2(rounds)=init_cwnd×2rounds

C

w

n

d

=

f

2

(

r

o

u

n

d

s

)

=

i

n

i

t

_

c

w

n

d

×

2

r

o

u

n

d

s

因此,在推导bbr_high_gain时,可以沿着两条路分别进行,我们先沿着
PacingRate

P

a

c

i

n

g

R

a

t

e

积分到
Cwnd

C

w

n

d

这条路推导出
Cwnd

C

w

n

d

视角的bbr_high_gain,然后再通过
Cwnd

C

w

n

d

求导到
PacingRate

P

a

c

i

n

g

R

a

t

e

这条路来验算。

假设在第
n

n

RTT时其
PacingRate

P

a

c

i

n

g

R

a

t

e


R0×2n

R

0

×

2

n

,那么在下一个
RTT

R

T

T

,即
n+1

n

+

1


RTT

R

T

T

时,它的
PacingRate

P

a

c

i

n

g

R

a

t

e

就会变成
R0×2n+1

R

0

×

2

n

+

1

,多了
2n

2

n


R0

R

0

,在Startup阶段,
Cwnd

C

w

n

d

也遵循同样的演化规律。

为了推导简单,我们将设
R0

R

0


InitCwnd

I

n

i

t

C

w

n

d


RTT

R

T

T

均为
1

1

来归一化,同时用自变量x表示以一个
RTT

R

T

T

为单位的轮数,上面的式子可以写成:


PacingRate=f1(x)=2x

P

a

c

i

n

g

R

a

t

e

=

f

1

(

x

)

=

2

x



Cwnd=f2(x)=2x

C

w

n

d

=

f

2

(

x

)

=

2

x

而我们知道,
BDP

B

D

P


PacingRate

P

a

c

i

n

g

R

a

t

e

在时间上的积分(忽略常数C)。根据我们的假设,我们是按
RTT

R

T

T

轮数来计数的,所以一个
RTT

R

T

T

单位内的
BDP

B

D

P

就是一个关于
PacingRate

P

a

c

i

n

g

R

a

t

e

定积分

这里写图片描述

按照牛顿-莱布尼兹定理则有:


BDPlastrtt=F(x)|xx1=xx12xdx=2x2ln2

B

D

P

l

a

s

t

r

t

t

=

F

(

x

)

|

x

1

x

=

x

1

x

2

x

d

x

=

2

x

2

ln

2

抽掉
BDP

B

D

P

中的时间维度,在数值上它的意义就是
Cwnd

C

w

n

d


G

G

为增益系数,根据间隔一个RTT时其
Cwnd

C

w

n

d

的关系,则有:


F(x)|xx1=G×f2(x2)

F

(

x

)

|

x

1

x

=

G

×

f

2

(

x

2

)

化简可以得到:


2x2ln2=G×2x4

2

x

2

ln

2

=

G

×

2

x

4

所以,我们就得到了
G

G

G=2ln2


接下来,我们来沿着从
Cwnd

C

w

n

d


PacingRate

P

a

c

i

n

g

R

a

t

e

这条路来再走一遍,看看求出的增益系数是不是同一个值。

我们知道,发送量的变化率其实就是发送速率,因此对
Cwnd

C

w

n

d

关于时间求导,就可以得到速率:


g(x)=f2(x)=(2x)=2xln2

g

(

x

)

=

f

2

(

x

)

=

(

2

x

)

=

2

x

ln

2


α

α


PacingRate

P

a

c

i

n

g

R

a

t

e

的增益系数,则有:


g(x+1)=α×g(x)=α×2xln2

g

(

x

+

1

)

=

α

×

g

(

x

)

=

α

×

2

x

ln

2

经过
α

α

演化的
PacingRate

P

a

c

i

n

g

R

a

t

e

恰好就是
f1(x+1)

f

1

(

x

+

1

)

的数值:


f1(x+1)=α×g(x)=2x+1=α×2xln2

f

1

(

x

+

1

)

=

α

×

g

(

x

)

=

2

x

+

1

=

α

×

2

x

ln

2

所以,我们可以求出
α

α

的数值:


α=2ln2

α

=

2

ln

2

可以看出,这里的
PacingRate

P

a

c

i

n

g

R

a

t

e

的增益和前面的
Cwnd

C

w

n

d

增益在数值上是完全一致的,这也就是TCP BBR中的那个魔数
2ln2

2

ln

2

的由来。


如果你足够细心,你会发现上面的推导中有一个破绽。比如,既然
f1(x)=f2(x)

f

1

(

x

)

=

f

2

(

x

)

,而
g(x)

g

(

x

)

又由
f1(x)

f

1

(

x

)

求导产生,
g(x)

g

(

x

)


f2(x)

f

2

(

x

)

均表示
PacingRate

P

a

c

i

n

g

R

a

t

e

时,显然而然的是:


g(x)f2(x)

g

(

x

)

f

2

(

x

)

!!
其实,函数
f1

f

1


f2

f

2

之所以这么写是因为它们在离散的
RTT

R

T

T

上表现得确实如此,但在实际中,速率计算,
Cwnd

C

w

n

d

计算并非总是由平滑均匀的ACK事件来触发的,所以说就必须用一条光滑的曲线来尽量拟合离散的点,因此,上面的
f1(x)

f

1

(

x

)


f2(x)

f

2

(

x

)

本身就不是光滑曲线,它们和
g(x)

g

(

x

)

本身就不是同一条曲线。

实际上,
f1(x)

f

1

(

x

)


f2(x)

f

2

(

x

)

表示的均是折线,所要做的正是用光滑的曲线去拟合折线上那些离散的转折点,所以说,只能用增益系数代入去解方程,而不是直接让两个函数相等。


f1

f

1


f2

f

2

的图像类似下面这样:

这里写图片描述

我们再把代表
BDP

B

D

P

的平滑拟合曲线
F(x)

F

(

x

)

以及代表
PacingRate

P

a

c

i

n

g

R

a

t

e

的平滑拟合曲线
g(x)

g

(

x

)

画到同一个坐标系中:

这里写图片描述

可以看得出,它们是3样不同的曲线。

不过,看起来
F(x)

F

(

x

)


g(x)

g

(

x

)

对离散的
f1(x)

f

1

(

x

)


f2(x)

f

2

(

x

)

拟合得并不是很理想,那为什么不直接用
f(x)=2x

f

(

x

)

=

2

x

来拟合呢?它可是能完美拟合的吧:

这里写图片描述

或者,我们可以用二项式去拟合,用级数…

然而这些都不行。为什么呢?因为要考虑到计算,这里并不是在解一道数学题,而是要求出一个确定的常数作为增益系数
G

G

,注意,是确定的常数。如果不通过积分或者求导的方式引入一个ln2因子,单纯的
f(x)=2x

f

(

x

)

=

2

x

是无法得到一个确定的常数的。


这种方法,我们感到似曾相识,TCP的拥塞控制算法,从BIC到CUBIC就是采用了这种光滑的三次曲线拟合BIC二分折线的方法,其中的那些参数也可以用类似的方法求解。


除此之外,以上推导中,下面的关系是不存在的:


f1(x+1)=α×f1(x)

f

1

(

x

+

1

)

=

α

×

f

1

(

x

)



f2(x+1)=α×f2(x)

f

2

(

x

+

1

)

=

α

×

f

2

(

x

)

为什么?因为
f1(x)

f

1

(

x

)


f2(x)

f

2

(

x

)

上的点是离散的,非连续函数在无定义的域上求值没有意义。然而ACK的到达并非以RTT为单位准点的,更有可能遭遇ACK丢失,ACK聚集等无法预知的时间,因此ACK到达是任意的,所以就必须用光滑的曲线来拟合这些离散的点,从而达到比较平滑的增益效果。

简单点说,增益系数
G

G

的结果是针对光滑的拟合曲线而言的,即针对g(x)以及
F(x)

F

(

x

)

的,而不是针对
f1(x)

f

1

(

x

)


f2(x)

f

2

(

x

)

的。

原文链接: https://blog.csdn.net/dog250/article/details/80660091

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    TCP BBR的startup bbr_high_gain为什么是2/ln2?

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/406896

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午10:22
下一篇 2023年4月26日 上午10:22

相关推荐