溫州皮鞋廠老闆上周就一直在問這個。正好昨天和今天早上有空,加上又在雨夜,就寫一波。
溫州皮鞋廠老闆的問題如下:
慢啟動: init_cwnd×2n=cwnd i n i t _ c w n d × 2 n = c w n d
增長速率為 2n 2 n 求導= n×2n−1 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 * / + ;
另外,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 個RTTRTT時其 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 來歸一化,同時用自變量xx表示以一個 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)|xx−1=∫xx−12xdx=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 為增益系數,根據間隔一個RTTRTT時其 Cwnd C w n d 的關系,則有:
F(x)|xx−1=G×f2(x−2) 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=2ln2G=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 ,注意,是确定的常數。如果不通過積分或者求導的方式引入一個ln2ln2因子,單純的 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)g(x)以及 F(x) F ( x ) 的,而不是針對 f1(x) f 1 ( x ) 和 f2(x) f 2 ( x ) 的。