寫本文的初衷一部分來自于工作,更多的來自于發(fā)現(xiàn)國內(nèi)幾乎還沒有中文版的關(guān)于TCP bbr算法的文章,我想搶個(gè)沙發(fā)。
本文的寫作方式可能稍有不同,之前很多關(guān)于OpenVPN,Netfilter,IP路由,TCP的文章中,我都是先羅列了問題,然后闡述如何解決這個(gè)問題。但是本文不同!本文的內(nèi)容來自于我十分厭惡的一個(gè)領(lǐng)域,其中又牽扯到我十分厭惡的一家公司-華夏創(chuàng)新(Appex),這些令我厭惡的東西讓我不得不放棄很多的東西。所以,我不會(huì)先說業(yè)界遇到了什么問題,而是直接步入主題,闡述bbr算法的組成。我十分討厭與人談?wù)撽P(guān)于TCP擁塞控制的話題,一方面是因?yàn)檫@個(gè)話題太過發(fā)散,任何人都可以說出自己的理由讓人信服自己的忽悠人的算法,另一方面,我覺得我接觸到的所有人當(dāng)中并沒有人真的懂這些(當(dāng)然,我也不懂!而且比那些人更加不懂?。?,所以我寧可花些時(shí)間在預(yù)研或者研發(fā)上,我也不想跟人瞎逼逼或者聽別人瞎逼逼。
隨便提出一個(gè)TCP擁塞算法,任何人都可以做到說它好,任何人也可以做到說它不好,因?yàn)闆]人真的懂網(wǎng)絡(luò),所以聊這些是沒有意義的!TCP不是網(wǎng)絡(luò)范疇的技術(shù),它是控制論范疇的,TCP技術(shù)不屬于網(wǎng)絡(luò)技術(shù)!
我的觀點(diǎn)是,正確的做法只有一種,其它的都是錯(cuò)誤的做法,都沒有意義!
國慶節(jié)前,我看到了bbr算法,發(fā)現(xiàn)它就是那個(gè)唯一正確的做法(可能有點(diǎn)夸張,但起碼它是一個(gè)通往正確道路的起點(diǎn)?。?,所以花了點(diǎn)時(shí)間研究了一下它,包括其patch的注釋,patch代碼,并親自移植了bbr patch到更低版本的內(nèi)核,在這個(gè)過程中,我也產(chǎn)生了一些想法,作為備忘,整理了一篇文章,記如下,多年以后,再看TCP bbr算法的資料時(shí),我的記錄也算是中文社區(qū)少有的第一個(gè)吃螃蟹記錄了,也算夠了!
正文之前,給出本文的圖例:
使用BBR之前
我希望更多的人試用這個(gè)算法,并且與我共享測試結(jié)果,包括但不限于算法的帶寬利用率,搶占性等!特別是溫州皮鞋產(chǎn)老板!這個(gè)算法并不是我寫的,既然開源那就不應(yīng)該封閉于任何公司或者個(gè)人,所以我有權(quán)在這里就我知道的東西述說一二。
我深深地明白,我以下寫的這些有很多理解不周到的地方,我也深深的明白很多傳統(tǒng)學(xué)生出身的人不會(huì)告訴我那些疏漏,我指的是溫州老板那樣的人,因?yàn)樗麄儙缀醵际窃谒魅《环窒?,如果他們發(fā)現(xiàn)了我的疏漏,他們會(huì)默默記上一筆,到頭來他們學(xué)會(huì)了我分享的東西,他們又改進(jìn)了我的疏漏(但是并不告訴我?。?,他們又擁有自己獨(dú)立學(xué)會(huì)的那些東西(他們也不會(huì)告訴我?。?,所以,最終,他們?nèi)魏稳硕急任腋硬W(xué)且高明!然而不幸的是,這就是我的目標(biāo),我并不在乎那些人,我甚至不會(huì)在乎自己!
所以,趕緊試用bbr吧,趕緊改進(jìn)吧,功勞是你的,虛無是我的!
BBR的組成
bbr算法實(shí)際上非常簡單,在實(shí)現(xiàn)上它由5部分組成:
1.即時(shí)速率的計(jì)算
計(jì)算一個(gè)即時(shí)的帶寬bw,該帶寬是bbr一切計(jì)算的基準(zhǔn),bbr將會(huì)根據(jù)當(dāng)前的即時(shí)帶寬以及其所處的pipe狀態(tài)來計(jì)算pacing rate以及cwnd(見下文),后面我們會(huì)看到,這個(gè)即時(shí)帶寬計(jì)算方法的突破式改進(jìn)是bbr之所以簡單且高效的根源。計(jì)算方案按照標(biāo)量計(jì)算,不再關(guān)注數(shù)據(jù)的含義。在bbr運(yùn)行過程中,系統(tǒng)會(huì)跟蹤當(dāng)前為止最大的即時(shí)帶寬。
2.RTT的跟蹤
bbr之所以可以獲取非常高的帶寬利用率,是因?yàn)樗梢苑浅0踩液婪诺靥綔y到帶寬的最大值以及rtt的最小值,這樣計(jì)算出來的BDP就是目前為止TCP管道的最大容量。bbr的目標(biāo)就是達(dá)到這個(gè)最大的容量!這個(gè)目標(biāo)最終驅(qū)動(dòng)了cwnd的計(jì)算。在bbr運(yùn)行過程中,系統(tǒng)會(huì)跟蹤當(dāng)前為止最小RTT。
3.bbr pipe狀態(tài)機(jī)的維持
bbr算法根據(jù)互聯(lián)網(wǎng)的擁塞行為有針對性地定義了4中狀態(tài),即STARTUP,DRAIN,PROBE_BW,PROBE_RTT。bbr通過對上述計(jì)算的即時(shí)帶寬bw以及rtt的持續(xù)觀察,在這4個(gè)狀態(tài)之間自由切換,相比之前的所有擁塞控制算法,其革命性的改進(jìn)在于bbr擁塞算法不再跟蹤系統(tǒng)的TCP擁塞狀態(tài)機(jī),而旨在用統(tǒng)一的方式來應(yīng)對pacing rate和cwnd的計(jì)算,不管當(dāng)前TCP是處在Open狀態(tài)還是處在Disorder狀態(tài),抑或已經(jīng)在Recovery狀態(tài),換句話說,bbr算法感覺不到丟包,它能看到的就是bw和rtt!
4.結(jié)果輸出-pacing rate和cwnd
首先必須要說一下,bbr的輸出并不僅僅是一個(gè)cwnd,更重要的是pacing rate。在傳統(tǒng)意義上,cwnd是TCP擁塞控制算法的唯一輸出,但是它僅僅規(guī)定了當(dāng)前的TCP最多可以發(fā)送多少數(shù)據(jù),它并沒有規(guī)定怎么把這么多數(shù)據(jù)發(fā)出去,在Linux的實(shí)現(xiàn)中,如果發(fā)出去這么多數(shù)據(jù)呢?簡單而粗暴,突發(fā)!忽略接收端通告窗口的前提下,Linux會(huì)把cwnd一窗數(shù)據(jù)全部突發(fā)出去,而這往往會(huì)造成路由器的排隊(duì),在深隊(duì)列的情況下,會(huì)測量出rtt劇烈地抖動(dòng)。
bbr在計(jì)算cwnd的同時(shí),還計(jì)算了一個(gè)與之適配的pacing rate,該pacing rate規(guī)定cwnd指示的一窗數(shù)據(jù)的數(shù)據(jù)包之間,以多大的時(shí)間間隔發(fā)送出去。
5.其它外部機(jī)制的利用-fq,rack等
bbr之所以可以高效地運(yùn)行且如此簡單,是因?yàn)楹芏鄼C(jī)制并不是它本身實(shí)現(xiàn)的,而是利用了外部的已有機(jī)制,比如下一節(jié)中將要闡述的它為什么在計(jì)算帶寬bw時(shí)能如此放心地將重傳數(shù)據(jù)也計(jì)算在內(nèi)。..
帶寬計(jì)算細(xì)節(jié)以及狀態(tài)機(jī)
1.即時(shí)帶寬的計(jì)算
bbr作為一個(gè)純粹的擁塞控制算法,完全忽略了系統(tǒng)層面的TCP狀態(tài),計(jì)算帶寬時(shí)它僅僅需要兩個(gè)值就夠了:
1)。應(yīng)答了多少數(shù)據(jù),記為delivered;
2)。應(yīng)答1)中的delivered這么多數(shù)據(jù)所用的時(shí)間,記為interval_us。
將上述二者相除,就能得到帶寬:
bw = delivered/interval_us
非常簡單!以上的計(jì)算完全是標(biāo)量計(jì)算,只關(guān)注數(shù)據(jù)的大小,不關(guān)注數(shù)據(jù)的含義,比如delivered的采集中,bbr根本不管某一個(gè)應(yīng)答是重傳后的ACK確認(rèn)的,正常ACK確認(rèn)的,還是說SACK確認(rèn)的。bbr只關(guān)心被應(yīng)答了多少!
這和TCP/IP網(wǎng)絡(luò)模型是一致的,因?yàn)樵谥虚g鏈路上,路由器交換機(jī)們也不會(huì)去管這些數(shù)據(jù)包是重傳的還是亂序的,然而擁塞也是在這些地方發(fā)生的,既然擁塞點(diǎn)都不關(guān)心數(shù)據(jù)的意義,TCP為什么要關(guān)注呢?反過來,我們看一下?lián)砣l(fā)生的原因,即數(shù)據(jù)量超過了路由器的帶寬限制,利用這一點(diǎn),只需要精心地控制發(fā)送的數(shù)據(jù)量就好了,完全不用管什么亂序,重傳之類的。當(dāng)然我的意思是說,擁塞控制算法中不用管這些,但這并不意味著它們是被放棄的,其它的機(jī)制會(huì)關(guān)注的,比如SACK機(jī)制,RACK機(jī)制,RTO機(jī)制等。
接下來我們看一下這個(gè)delivered以及interval_us的采集是如何實(shí)現(xiàn)的。還是像往常一樣,我不準(zhǔn)備分析源碼,因?yàn)槿绻治鲈创a的話,往往難以抓住重點(diǎn),過一段時(shí)間自己也看不懂了,相反,畫圖的話,就可以過濾掉很多諸如unlikely等異常流或者當(dāng)前無需關(guān)注的東西:
上圖中,我故意用了一個(gè)極端點(diǎn)的例子,在該例子中,我?guī)缀醵际鞘褂玫腟ACK,當(dāng)X被SACK時(shí),我們可以根據(jù)圖示很容易算出從Delivered為7時(shí)的數(shù)據(jù)包被確認(rèn)到X被確認(rèn)為止,一共有 12-7=5個(gè)數(shù)據(jù)包被確認(rèn),即這段時(shí)間網(wǎng)絡(luò)上清空了5個(gè)數(shù)據(jù)包!我們便很容易算出帶寬值了。我的這個(gè)圖示在解釋帶寬計(jì)算方法之外,還有一個(gè)目的,即說明bbr在計(jì)算帶寬時(shí)是不關(guān)注數(shù)據(jù)包是否按序確認(rèn)的,它只關(guān)注數(shù)量,即數(shù)據(jù)包被網(wǎng)絡(luò)清空的數(shù)量。實(shí)實(shí)在在的計(jì)算,不猜Lost,不猜亂序,這些東西,你再怎么猜也猜不準(zhǔn)!
計(jì)算所得的bw就是bbr此后一切計(jì)算的基準(zhǔn)。
2.狀態(tài)機(jī)
bbr的狀態(tài)機(jī)轉(zhuǎn)換圖以及注釋如下圖所示:
通過上述的狀態(tài)機(jī)以及上一節(jié)的帶寬計(jì)算方式,我們知道了bbr的工作方式:不斷地基于當(dāng)前帶寬以及當(dāng)前的增益系數(shù)計(jì)算pacing rate以及cwnd,以此2個(gè)結(jié)果作為擁塞控制算法的輸出,在TCP連接的持續(xù)過程中,每收到一個(gè)ACK,都會(huì)計(jì)算即時(shí)的帶寬,然后將結(jié)果反饋給bbr的pipe狀態(tài)機(jī),不斷地調(diào)節(jié)增益系數(shù),這就是bbr的全部,我們發(fā)現(xiàn)它是一個(gè)典型的封閉反饋系統(tǒng),與TCP當(dāng)前處于什么擁塞狀態(tài)完全無關(guān),其簡圖如下:
這非常不同于之前的所有擁塞控制算法,在之前的算法中,我們發(fā)現(xiàn)擁塞算法內(nèi)部是受外部的擁塞狀態(tài)影響的,比如說在Recovery狀態(tài)下,甚至都不會(huì)進(jìn)入擁塞控制算法,在bbr進(jìn)入內(nèi)核之前,Linux使用PRR算法控制了Recovery狀態(tài)的窗口調(diào)整,即便說這個(gè)時(shí)候網(wǎng)絡(luò)已經(jīng)恢復(fù),TCP也無法發(fā)現(xiàn),因?yàn)門CP的Recovery狀態(tài)還未恢復(fù)到Open,這就是根源!
pacing rate以及cwnd的計(jì)算
這一節(jié)好像是重點(diǎn)中的重點(diǎn),但是我覺得如果理解了bbr的帶寬計(jì)算,狀態(tài)機(jī)以及其增益系數(shù)的概念,這里就不是重點(diǎn)了,這里只是一個(gè)公式化的結(jié)論。
pacing rate怎么計(jì)算?很簡單,就是是使用時(shí)間窗口內(nèi)(默認(rèn)10輪采樣)最大BW。上一次采樣的即時(shí)BW,用它來在可能的情況下更新時(shí)間窗口內(nèi)的BW采樣值集合。這次能否按照這個(gè)時(shí)間窗口內(nèi)最大BW發(fā)送數(shù)據(jù)呢?這樣看當(dāng)前的增益系數(shù)的值,設(shè)為G,那么BW*G就是pacing rate的值,是不是很簡單呢?!
至于說cwnd的計(jì)算可能要稍微復(fù)雜一點(diǎn),但是也是可以理解的,我們知道,cwnd其實(shí)描述了一條網(wǎng)絡(luò)管道(rwnd描述了接收端緩沖區(qū)),因此cwnd其實(shí)就是這個(gè)管道的容量,也就是BDP!
BW我們已經(jīng)有了,缺少的是D,也就是RTT,不過別忘了,bbr一直在持續(xù)搜集最小的RTT值,注意,bbr并沒有采用什么移動(dòng)指數(shù)平均算法來“猜測”RTT(我用猜測而不是預(yù)測的原因是,猜測的結(jié)果往往更加不可信?。侵苯用芭莶杉钚〉腞TT(注意這個(gè)RTT是TCP系統(tǒng)層面移動(dòng)指數(shù)平均的結(jié)果,即SRTT,但brr并不會(huì)對此結(jié)果再次做平均?。N覀冇眠@個(gè)最小RTT干什么呢?
當(dāng)前是計(jì)算BDP了!這里bbr取的RTT就是這個(gè)最小RTT。最小RTT表示一個(gè)曾經(jīng)達(dá)到的最佳RTT,既然曾經(jīng)達(dá)到過,說明這是客觀的可以再次達(dá)到的RTT,這樣有益于網(wǎng)絡(luò)管道利用率最大化!
我們采用BDP*G‘就算出了cwnd,這里的G’是cwnd的增益系數(shù),與帶寬增益系數(shù)含義一樣,根據(jù)bbr的狀態(tài)機(jī)來獲?。?/p>
bbr的細(xì)節(jié)淺述
該節(jié)的題目比較怪異,既然是細(xì)節(jié)為什么又要淺述??
這是我的風(fēng)格,一方面,說是細(xì)節(jié)是因?yàn)檫@些東西還真的很少有人注意到,另一方面,說是淺述,是因?yàn)槲乙话愣疾粫?huì)去分析代碼以及代碼里每一個(gè)異常流,我認(rèn)為那些對于理解原理幫助不大,那些東西只是在研發(fā)和優(yōu)化時(shí)才是有用的,所以說,像往常一樣,我這里的這個(gè)小節(jié)還是一如既往地去談及一些“細(xì)節(jié)”。
1.豪放且大膽的安全探測
在看到bbr之后,我覺得之前的TCP擁塞控制算法都錯(cuò)了,并不是思想錯(cuò)了,而是實(shí)現(xiàn)的問題。
bbr之所以敢大膽的去探測預(yù)估帶寬是因?yàn)門CP把更多的權(quán)力交給了它!在bbr之前,很多本應(yīng)該由擁塞控制算法去處理的細(xì)節(jié)并不歸擁塞控制算法管。在詳述之前,我們必須分清兩件事:
1)。傳輸多少數(shù)據(jù)?
2)。傳輸哪些數(shù)據(jù)?
按照“上帝的事情上帝管,凱撒的事情凱撒管”的原則,這兩件事本來就該由不同的機(jī)制來完成,不考慮對端接收窗口的情況下,擁塞窗口是唯一的主導(dǎo)因素,“傳輸多少數(shù)據(jù)”這件事應(yīng)該由擁塞算法來回答,而“傳輸哪些數(shù)據(jù)”這個(gè)問題應(yīng)該由TCP擁塞狀態(tài)機(jī)以及SACK分布來決定,誠然這兩個(gè)問題是不同的問題,不應(yīng)該雜糅在一起。
然而,在bbr進(jìn)入內(nèi)核之前的Linux TCP實(shí)現(xiàn)中,以上兩個(gè)問題并不是分得特別清。TCP的擁塞狀態(tài)只有在Open時(shí)才是上述的職責(zé)分離的完美樣子,一旦進(jìn)入Lost或者Recovery,那么擁塞控制算法即便對“問題1):傳輸多少數(shù)據(jù)”都無能為力,在Linux的現(xiàn)有實(shí)現(xiàn)中,PRR算法將接管一切,一直把窗口下降到ssthresh,在Lost狀態(tài)則反應(yīng)更加激烈,直接cwnd硬著陸!隨后等丟失數(shù)據(jù)傳輸成功后再執(zhí)行慢啟動(dòng)。..。在重新進(jìn)入Open狀態(tài)之前,擁塞控制算法幾乎不會(huì)起作用,這并不是一種高速公路上的模式(小碰擦,拍照后??柯愤?,自行解決),更像是鬧市區(qū)的交通事故處理方式(無論怎樣,保持現(xiàn)場,直到交警和保險(xiǎn)公司的人來現(xiàn)場處置)。
bbr算法逃離了這一切錯(cuò)誤的做法,在bbr的patch中,并非只是完成了一個(gè)tcp_bbr.c,而是對整個(gè)TCP擁塞狀態(tài)控制框架進(jìn)行了大手術(shù),我們可以從以下的擁塞控制核心函數(shù)中可見一斑:
static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked,
int flag, const struct rate_sample *rs)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
if (icsk-》icsk_ca_ops-》cong_control) {
// 如果是bbr,則完全被bbr接管,不管現(xiàn)在處在什么狀態(tài)!
/* 目前而言,只有bbr使用了這個(gè)機(jī)制,但我相信,不久的將來,
* 會(huì)有越來越多的擁塞控制算法使用這個(gè)統(tǒng)一的完全接管機(jī)制!
* 就我個(gè)人而言,在幾個(gè)月前就寫過一個(gè)patch,接管了tcp_cwnd_reduction
* 這個(gè)prr的降窗過程。如果當(dāng)時(shí)有了這個(gè)框架,我就有福了!
*/
icsk-》icsk_ca_ops-》cong_control(sk, rs);
return;
}
// 否則繼續(xù)以往的錯(cuò)誤方法!
if (tcp_in_cwnd_reduction(sk)) {
/* Reduce cwnd if state mandates */
// 非Open狀態(tài)中擁塞算法不受理窗口調(diào)整
tcp_cwnd_reduction(sk, acked_sacked, flag);
} else if (tcp_may_raise_cwnd(sk, flag)) {
/* Advance cwnd if state allows */
tcp_cong_avoid(sk, ack, acked_sacked);
}
tcp_update_pacing_rate(sk);
}
在這個(gè)框架下,無論處在哪個(gè)狀態(tài)(Open,Disorder,Recovery,Lost.。.),如果擁塞控制算法自己聲明有這個(gè)能力,那么具體可以傳輸多少數(shù)據(jù),完全由擁塞控制算法自行決定,TCP擁塞狀態(tài)控制機(jī)制不再干預(yù)!
2.為什么bbr可以忽略Recovery和Lost狀態(tài)
看懂了以上第1點(diǎn),這一點(diǎn)就很容易理解了。
在第1點(diǎn)中,我描述了bbr確實(shí)忽略了Recovery等非Open的擁塞狀態(tài),但是為什么可以忽略呢?一般而言,很多人都會(huì)質(zhì)疑,會(huì)說bbr采用這么魯莽的方式,最終一定會(huì)讓窗口卡住不再滑動(dòng),但是我要反駁,你難道不知道cwnd只是個(gè)標(biāo)量嗎?我畫一個(gè)圖來分析:
看懂了嗎?不存在任何問題!基本上,我們在討論擁塞控制算法的時(shí)候,會(huì)忽略流量控制,因?yàn)椴幌胱宺wnd和cwnd雜糅起來,但是在這里,它們相遇了,幸運(yùn)的是,并沒有引發(fā)沖突!
然而,這并不是全部,本節(jié)旨在“淺析”,因此就不會(huì)關(guān)注代碼處理的細(xì)節(jié)。在bbr的實(shí)現(xiàn)中,如果算法外部的TCP擁塞狀態(tài)已經(jīng)進(jìn)入了Lost,那么cwnd該是多少呢?在bbr之前的擁塞算法中,包括cubic在內(nèi)的所有算法中,當(dāng)TCP核心實(shí)現(xiàn)從將cwnd調(diào)整到1或者prr到ssthresh一直到恢復(fù)到Open狀態(tài),擁塞算法無權(quán)干預(yù)流程,然而bbr不。雖然說進(jìn)入Lost狀態(tài)后,cwnd會(huì)硬著陸到1,然而由于bbr的接管,在Lost期間,cwnd還是可以根據(jù)即時(shí)帶寬調(diào)整的!
這意味著什么?
這意味著bbr可以區(qū)別噪聲丟包和擁塞丟包了!
a)。噪聲丟包
如果是噪聲丟包,在收到reordering個(gè)重復(fù)ACK后,由于bbr并不區(qū)分一個(gè)確認(rèn)是ACK還是SACK引起的,所以在bbr看來,即時(shí)帶寬并沒有降低,可能還有所增加,所以一個(gè)數(shù)據(jù)包的丟失并不會(huì)引發(fā)什么,bbr依舊會(huì)給出一個(gè)比較大的cwnd配額,此時(shí)雖然TCP可能已經(jīng)進(jìn)入了Recovery狀態(tài),但bbr依舊按照自己的bw以及調(diào)整后的增益系數(shù)來計(jì)算cwnd的新值,過程中并不會(huì)受到任何TCP擁塞狀態(tài)的影響。
如此一來,所有的噪聲丟包就被區(qū)別開來了!bbr的宗旨是:“首先,在我的bw計(jì)算指示我發(fā)生擁塞之前,任何傳統(tǒng)的TCP擁塞判斷-丟包/時(shí)延增加,均全部失效,我并不care丟包和RTT增加”,隨后brr又會(huì)說:“但是我比較care的是,RTT在一段時(shí)間內(nèi)(隨你怎么配,但我個(gè)人傾向于自學(xué)習(xí))都沒有達(dá)到我所采集到的最小值或者更小的值!這也許意味著著鏈路真的發(fā)生擁塞了!”。..
b)。擁塞丟包
將a)的論述反過來,我們就會(huì)得到奇妙的封閉性結(jié)論。這樣,bbr不光是消除了吞吐曲線的鋸齒(ssthresh所致,bbr并不使用ssthresh!),而且還消除了傳統(tǒng)擁塞控制算法(指bbr以及封閉的傻逼Appex之前)的判斷滯后性問題。在cubic發(fā)現(xiàn)丟包進(jìn)而判斷為擁塞時(shí),擁塞可能已經(jīng)緩解了,但是cubic無法發(fā)現(xiàn)這一點(diǎn)。為什么?原因在于cubic在計(jì)算新的cwnd的時(shí)候,并沒有把當(dāng)前的網(wǎng)絡(luò)狀態(tài)(比如bw)當(dāng)作參數(shù),而只是一味的按照數(shù)學(xué)意義上的三次方程去計(jì)算,這是錯(cuò)誤的,這不是一個(gè)正確的反饋系統(tǒng)的做法!
基于a)和b),看到了吧,這就是新的擁塞判斷機(jī)制!綜合考慮丟包和RTT的增加:
b-1)。如果丟包時(shí)真的發(fā)生了擁塞,那么測量的即時(shí)帶寬肯定會(huì)減少,否則,丟包即擁塞就是謊言。
b-2)。如果RTT增加時(shí)真的發(fā)生了擁塞,那么測量的即時(shí)帶寬肯定會(huì)減少,否則,時(shí)延增加即擁塞就是謊言。
bbr測量了即時(shí)帶寬,這個(gè)統(tǒng)一cwnd和rtt的計(jì)量,完全忽略了丟包,因此bbr的算法思想是TCP擁塞控制的正軌!事實(shí)上,丟包本就不應(yīng)該作為一種擁塞的標(biāo)志,它只是擁塞的表現(xiàn)。
3.狀態(tài)機(jī)的點(diǎn)點(diǎn)滴滴
我在上文已經(jīng)呈現(xiàn)了關(guān)于STARTUP,DRAIN,PROBE_BW,PROBE_RTT的狀態(tài)圖以及些許細(xì)節(jié),當(dāng)時(shí)我指出這個(gè)狀態(tài)圖的目標(biāo)是為了完成bbr的目標(biāo),即填滿整個(gè)網(wǎng)絡(luò)!在這個(gè)狀態(tài)圖看來,所有已知的東西就是當(dāng)前的即時(shí)帶寬,所有可以計(jì)算的東西就是增益系數(shù),然后根據(jù)這兩個(gè)元素就可以輕易計(jì)算出pacing rate和cwnd,是不是很簡單呢?整體看來就是就是這么簡單,但是從細(xì)節(jié)上看,不同的pipe狀態(tài)中的增益系數(shù)的計(jì)算卻是值得推敲的,以下是bbr處在各個(gè)狀態(tài)時(shí)的增益系數(shù):
STARTUP:2~3
DRAIN:pacing rate的增益系數(shù)為1000/2885,cwnd的增益系數(shù)為1000/2005+1。
PROBE_BW:5/4,1,3/4,bbr在PROBE_BW期間會(huì)隨機(jī)在這些增益系數(shù)之間選擇當(dāng)前的增益系數(shù)。
PROBE_RTT:1。但是在探測RTT期間,為了防止丟包,cwnd會(huì)強(qiáng)制cut到最小值,即4個(gè)MSS。
我們可以看到,bbr并沒有明確的所謂“降窗時(shí)刻”,一切都是按照狀態(tài)機(jī)來的,期間絲毫不會(huì)理會(huì)TCP是否處在Open,Recovery等狀態(tài)。在此前的擁塞控制算法中,除了Vegas等基于延時(shí)的算法會(huì)在計(jì)算得到的target cwnd小于當(dāng)前cwnd時(shí)視為擁塞而在算法中降窗外,其它的所有基于丟包的算法中均是檢測到丟包(RTO或者reordering個(gè)重復(fù)ACK)時(shí)降窗的,可悲的是,這個(gè)降窗過程并不受擁塞算法的控制,擁塞算法只能消極地給出一個(gè)ssthresh值,即降窗的目標(biāo),這顯然是令人無助的!
bbr不再關(guān)注丟包事件,它并不把丟包當(dāng)成很嚴(yán)重的事,這事也不歸它管,只要TCP擁塞狀態(tài)機(jī)控制機(jī)制可以合理地將一些包標(biāo)記為LOST,然后重傳它們便是了,bbr能做的僅僅是告訴TCP一共可以發(fā)出去多少數(shù)據(jù),僅此而已!然而,如果TCP并沒有把LOST數(shù)據(jù)包合理標(biāo)記好,bbr并不care,它只是根據(jù)當(dāng)前的bw和增益系數(shù)給出下一個(gè)pacing rate以及cwnd而已!
4.關(guān)于Sched FQ
這里涉及的是bbr之外的東西,F(xiàn)air queue!在bbr的patch最后,會(huì)發(fā)現(xiàn)幾行注釋:
NOTE: BBR *must* be used with the fq qdisc (“man tc-fq”) with pacing
enabled, since pacing is integral to the BBR design and
implementation. BBR without pacing would not function properly, and
may incur unnecessary high packet loss rates.
記住這幾行文字并理解它們。
這是bbr最為重要的一方面。雖然說Linux的TCP實(shí)現(xiàn)早就支持的pacing rate,但直到4.8版本都沒有在TCP層面支持它,很大的一部分原因是因?yàn)榻柚延械腇Q可以很完美地實(shí)現(xiàn)pacing rate!TCP可以借助FQ來實(shí)現(xiàn)平緩而非突發(fā)的數(shù)據(jù)發(fā)送!
關(guān)于FQ的詳細(xì)內(nèi)容可以去看相關(guān)的manual和源碼,這里要說的僅僅是,F(xiàn)Q可以根據(jù)bbr設(shè)置的pacing rate將一個(gè)cwnd內(nèi)的數(shù)據(jù)的發(fā)送從“突發(fā)到網(wǎng)絡(luò)”這種行為變換到“平緩發(fā)送到網(wǎng)路”的行為,所謂的平緩發(fā)送指的就是數(shù)據(jù)包是按照帶寬速率計(jì)算的間隔一個(gè)個(gè)發(fā)送到網(wǎng)絡(luò)的,而不是突發(fā)進(jìn)網(wǎng)絡(luò)的!
這樣一來,就給了網(wǎng)絡(luò)緩存以緩解的機(jī)會(huì)!記住,關(guān)鍵問題是bbr會(huì)在每收到ACK/SACK時(shí)計(jì)算bw,這個(gè)精確的測量不會(huì)漏掉任何可乘之機(jī),即便當(dāng)前網(wǎng)絡(luò)擁塞了,它只要能在下一時(shí)刻恢復(fù),bbr就可以發(fā)現(xiàn),因此即時(shí)帶寬通常可以表現(xiàn)這一點(diǎn)!
5.其它
還有關(guān)于令牌桶監(jiān)管發(fā)現(xiàn)(lt policed)的主題,long term采樣的主題,留到后面的文章具體闡述吧,本文已經(jīng)足夠長了。
6.bufferbloat問題
關(guān)于深隊(duì)列,數(shù)據(jù)包如何如何長時(shí)間排隊(duì)但不丟包卻引發(fā)RTO,對于淺隊(duì)列,數(shù)據(jù)包如何如何頻繁丟包。..談起這個(gè)話題我一開始想滔滔不絕,后來想罵人,現(xiàn)在我三緘其口!任何人都知道端到端的QoS是一個(gè)典型的反饋系統(tǒng),但是任何人都只是夸夸其談,我選擇的是閉口不說,如果非要我說,我的回答就是:不知道!
這是一個(gè)怎么說都能對又怎么說都能錯(cuò)的話題,就像股票預(yù)測那樣,所以我選擇閉嘴。
bbr算法到來后,單單從公共測試結(jié)果上看,貌似解決了bufferbloat問題,也許吧,也許。bbr好像真的開始在高速公路上飚車了。..最后給出一個(gè)測試圖,來自《A quick look at TCP BBR》:
bbr代碼的簡單性和復(fù)雜性
我一向覺得TCP擁塞控制算法太過復(fù)雜,而復(fù)雜的東西基本上就是用來裝逼的垃圾,直到遇到了bbr。
Neal Cardwell提供的patch簡單而又直接,大家可以從 該bbr的pach上一看究竟!在bbr模塊之外,Neal Cardwell主要更改了tcp_ack函數(shù)里面關(guān)于delivered計(jì)數(shù)的部分以及擁塞控制主函數(shù),這一切都十分顯然,只要patch代碼就可以一目了然。在數(shù)據(jù)包被發(fā)送的時(shí)候-不管是初次發(fā)送還是重傳,均會(huì)被當(dāng)前TCP的連接狀況記錄在該數(shù)據(jù)包的tcp_skb_cb中,在數(shù)據(jù)包被應(yīng)答的時(shí)候-不管是被ACK還是被SACK,均會(huì)根據(jù)當(dāng)前的狀態(tài)和其tcp_skb_cb中狀態(tài)計(jì)算出一個(gè)帶寬,這些顯而易見的邏輯相比任何人都應(yīng)該知道哪里的代碼被修改了!
然而,這種查找和確認(rèn)的工作太令人感到悲哀,讀懂代碼是容易的,移植代碼是無聊的,因?yàn)闀r(shí)間卡的太緊!我必須要說的是,如果一件感興趣的事情變成了必須要完成的工作,那么做它的激情起碼減少了1/4,OK,還不算太壞,然而如果這個(gè)必須完成的工作有了deadline,那么激情就會(huì)再減少1/4,最后,如果有人在背后一直催,那么完蛋,這件事可以瞬間完成,但是我可以鄭重說明這是湊合的結(jié)果!但是實(shí)際上,這件事本應(yīng)該可以立即快速有高質(zhì)量的完成并驗(yàn)收!
寫在最后
我本來應(yīng)該可以把本文寫的更長些,但是打住了,因?yàn)槲覜]有時(shí)間,沒有精力,更沒有業(yè)務(wù)去繼續(xù),我寫這一切純粹是閑的,周末比較無聊,所以信手拈來幾筆畫了幾張圖,完成了本文。
我之所以不繼續(xù)下去的原因更多的是只是因?yàn)闆]有時(shí)間!我比較討厭急功近利,我比較喜歡工匠精神,一種時(shí)間打磨精品的精神,一種自由引導(dǎo)創(chuàng)造的精神,如果沒有時(shí)間,什么都是掰扯!
比較諷刺的是,這個(gè)bbr算法顯然不是一個(gè)“一周或者兩周搞定的算法”,但是中國人卻希望花更少的時(shí)間去將其“拿來”就用。..。中國人認(rèn)為任何事情都是可以靠加班可以解決的,所謂愚公移山,精衛(wèi)填海,鐵杵磨針,人心齊泰山移的精神早已深入人心,殊不知這種XX行徑根本經(jīng)不起推敲,你把全中國14億不止的人聚集起來一起去推泰山,看能推得動(dòng)么?你真的用一根鐵杵去磨針么?為什么不去想著買針!?傻逼!我不說了,本文所寫的技術(shù)中透露的態(tài)度,與生活無關(guān),亦與工作無關(guān),這種態(tài)度完全是我自己一個(gè)人的世界,與不理解以及反對的人,不討論,不爭論,不辯論。..!技術(shù)是大家的,態(tài)度是個(gè)人的。
編輯:hfy
評論
查看更多