深夜聊聊Bufferbloat以及TCP BBR
阿新 • • 發佈:2018-11-12
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
這篇文章的寫作動機來源於知乎上的一個問題,有人問既然Bufferbloat是個問題,為什麼路由器的快取還要設計那麼大。起初,我也是覺得快取越大越好,這個就像人們拼命比拼誰的電腦記憶體大一樣,因為在一般人眼裡,記憶體越大就越快!然而對於網路而言,恰好相反,記憶體越大,越讓人不想歸家。酒店舒適,但只是路過,沒人會把家裝修成酒店的樣子,家才是越大越好。
路由器設計成攜帶大快取的裝置,這是一個錯誤!路由器不該有那麼大的快取,然而TCP大牛當年的一個“AIMD錯誤決定”讓路由器的快取越來越大,最終引發了Bufferbloat!事情還要從安迪-比爾定律說起。
網路上的“安迪-比爾定律”
先解釋一下安迪-比爾定律,即“比爾.蓋茨拿走了安迪.格魯夫所給的”。狹義的講就是無論Intel的晶片快到多麼牛逼的地步,微軟的下一個Windows版本總是能把晶片的效能榨乾,然而廣義的講,安迪-比爾定律連同摩爾定律一起事實上構成了資訊產業的一臺泵,典型的一個正反饋系統,這是決定網際網路產業大爆發的本質原因,這個系統如下:
摩爾定律->硬體效能提升->軟體填補硬體提升的空間
我們可以理解為,摩爾定律和安迪-比爾定律驅動了資訊革命的車輪不斷滾動從而碾壓一切!
----------------------------
可以把路由器的越來越大的Buffer以及TCP貪婪地佔據這些路由器Buffer兩者看作是另一個“安迪-比爾定律”。因為BBR之前的TCP擁塞演算法都是盲目且貪婪的,路由器加大的Buffer總是能被TCP的AI(加性增窗)過程快速榨乾,反過來大快取延遲了TCP的丟包,同時增加了丟包的成本,這要求路由器提供更多的快取。
具體來講就是,如果路由器Buffer過小,基於丟包的擁塞演算法固有的全域性同步現象將會使得頻寬的利用率極低,所以必須增加Buffer來彌補。這就是一個正反饋迴圈,肇事者可以說是基於丟包的TCP演算法,它驅動了路由器Buffer越來越大,當Buffer越來越大,TCP又會瞬間用完,永遠喂不飽,直到永遠。
好在有摩爾定律和TCP的MD(乘性減窗)過程二者從中協調,如果同時失去了二者,TCP早晚會全域性崩潰!
我們假設硬體已經逼近了熱密度的極限,摩爾定律失效了,此時不會再增加Buffer的大小了,會發生什麼呢?
只要有TCP的MD過程在,網際網路就不會崩潰,所以說,TCP的AI過程保障了其效率,而MD過程則保證了收斂。
Google的新擁塞控制框架來了以後,MD過程便不被保證了,任何人都可以寫一個永不降窗的演算法,如果把主動的MD過程看作道德的話,那麼路由器的AQM就是法律了。這就是TCP/IP的幾乎全部內容了,我們可以看到,它極其複雜。
值得注意的是,TCP/IP的安迪-比爾定律展現的這種複雜性,其促進因素不是摩爾定律,而是“人們對頻寬的高利用率的追求”,因此便有了以下的關係:
提高頻寬利用率->路由器加大Buffer->TCP的AIMD填補加大的Buffer
其實,這完全是錯覺,TCP/IP的框架不該這麼複雜的。或許,AIMD根本就不需要,事實上,是路由器不斷加大的Buffer和AIMD一起縱容了壞事的頻繁發生。這一點正如人們不斷買新電腦,不斷買新手機,然而過不了多久,你依然會發現不管再新的機器都卡的要死一樣的道理,只不過,人們買的電腦也好,手機也好,它們的更新換代是摩爾定律驅動的,機器完全是個人所有的,你隨時可以跟著摩爾定律的節奏更新換代,然而對於網路裝置卻不是這樣。
網路裝置,比如路由器,交換機之類,它們只是整個TCP/IP系統的一個環節而已,機房裡面的裝置是不可能頻繁更新換代的,摩爾定律幾乎被它們所無視。雖然摩爾定律依舊影響著裝置的實際製造和升級,但由於這種週期相對較長,也就是可以忽略的了。但這裡面有一個不變的定論,那就是TCP幾乎全部都是以AIMD原則來運作的,UDP則是無限貪婪的。TCP的AI會造成主動丟包,這也是基於丟包的擁塞控制演算法的核心,而MD會造成全域性同步,這兩點無疑造成了頻寬利用率的低下,這是TCP的硬傷,不得不靠不斷加大的路由器Buffer來彌補,至少是延遲了悲劇的發生,在延遲悲劇的這段時間內,路由器當然希望端系統可以意識到事情正在悄悄起變化並採取一些措施。
......
AIMD,正如乙太網的CSMA/CD一樣,並不完美,但是可用。現在的人們在千兆乙太網出現之前,曾經推匯出一個結論,那就是依靠CSMA/CD是不可能達到千兆bps的,然而如今已經是萬兆甚至4萬兆了...如果說乙太網的載波監聽,衝突檢測是不必要且可被替換的,那麼TCP的AIMD也是不必要且可被替換的,二者簡直太像了!
Bufferbloat問題
我不想說TCP的AI/MD(加性增和乘性減)是錯誤的,我也不敢給出如此決絕的否定,然而,至少我想表達的是,在“安迪-比爾定律”的作用下,AI/MD是有問題的!什麼問題呢?Bufferbloat問題!
再次重申,路由器攜帶很大的Buffer,是錯誤的!路由器Buffer在夠用前提下越小越好,沒有Buffer,自然就不會bloat,本來無一物,何處惹塵埃?!但是不能沒有Buffer...Buffer到底是用來幹什麼的?到底多少合適?
Buffer其實就比較類似我們吃的食物,曾經,在物資貧乏的年代,大家都在追求要多吃,現在營養過剩了,則反過來了,要少吃,實際上,人體根本不需要太多的食物,夠用即可,人體大部分的精力要用來做更有意義的事情。同樣基於儲存/轉發TCP/IP網路上的路由器其根本任務不是做儲存,而是做轉發,儲存只是在理論上不得已的一個手段。我來解釋下是為什麼。
路由器的入口和出口分別接收到達的資料包和轉發資料包,一臺路由器上往往有多個介面同時全雙工地進行接收/轉發,資料包的到達頻率是統計意義上的,符合泊松分佈,然而資料包的傳送則是固有的介面速率,這是分組交換網的核心根基!路由器扮演什麼角色?它是一個典型的多服務檯排隊系統!所以路由器必須攜帶一個Buffer用來平滑泊松分佈的包到達和固定速率的包傳送之間的關係。
那麼,設計多大的Buffer合適呢?按照排隊理論的現成公式計算,夠用即可!
我們考慮極端一點的情況,如果我們把儲存佇列的Buffer設計成無窮大,從而轉發延遲也將是無窮大(因為排隊延遲會趨向無窮大),會發生什麼?無疑,這臺路由器將會變成一個超級儲存器,它將會擁有全世界所有的資訊!
爆炸!轉發裝置變成了儲存裝置!這就是Bufferbloat。注意,Bufferbloat的惡劣影響並不是會造成丟包,而是會無端增加無辜連線的延遲。這裡有個認識上的誤區,這種認識在中國人的思維中特別明顯。很多人會覺得Bufferbloat會造成“丟包反饋延遲增加”,其實丟不丟包是你自己的事,如果你通過RTT梯度檢測到了Bufferbloat,你依舊繼續猛發,結果被AQM給丟了,那完全是你自己全責,事實上,這個時候大家都應該全域性MD才對。
真正的危害在於,由於Bufferbloat造成了整個大Buffer被填充,所有的資料包都將等待一個固有的排隊延遲,這會嚴重影響任意經過的實時類應用!千萬別扯什麼QoS,區分服務,綜合服務,流量工程什麼的,這些要真有用,120救護車就不會被堵在路上了,請注意,事在人為,事在人不為。
----------------------------
我最喜歡的其實不是TCP/IP網路什麼的,而是城市規劃,道路規劃以及機械設計(2002年我的專業就是機械工程),我只是在2004年的時候初識了路由器,交換機之類的東西,發現自己竟然可以不用挖地剷土澆築建橋就可以完成一條自己想象中的道路,並且還有那麼多的現實場景,這不禁可以讓人隨時進入禪境...實際上,關於城市規劃,道路規劃以及機械設計也有很多電腦上的模擬器,但問題是它們畢竟只是模擬,是不真實的,而路由器,交換機是真實的,它們就擺在那,登入裝置開啟Monitor,我看到的是真實的東西,這與模擬器有大不同。
在後來的學習中,我發現路由器交換機之上有個TCP/IP,折騰起來一點也不比挖地剷土澆築建橋來的輕鬆,但至少除了搬機器,上架,插線之外,沒有什麼體力活了,也還好。
----------------------------
路由器Buffer是什麼?以高架路為例,它相當於上匝道前面的位置:
如果廣中路上匝道的匯入區修的短一些,那麼擁堵只會體現在上匝道或者廣中路路口,這種擁堵反饋到準備上高架的司機那裡,結果就是,要麼等,要麼繞,至少會阻止他們上主線匯入區去添堵,傷害無辜的流量。
好了,該回到TCP了。路由器Buffer減小有什麼好處呢?好處在於,即使有連線拼命去AI添堵,那麼丟包會很快到來,並且很快反饋給傳送方,於是傳送方會執行MD以表示懺悔,整個過程中,實時流量不會受到絲毫影響。
劣幣驅良幣
BBR是什麼我就不解釋了,我寫了很多文章。這些文章中沒有提到的是,BBR屬於那種即便上匝道匯入區修的再長也不上去添堵的德國好司機。那麼結果是什麼?你以為這種行為會感動全中國嗎?錯了,這正是中國人所期許的,你謙讓,我就流氓。你不去堵,我去堵。結果就是,BBR即便不去主動添堵,也會被其它人堵在路上,BBR只能說,這擁堵不是自己造成的,僅此而已。吃虧做好事又不被認可反被訛,這是我們這裡常有的事,BBR到了中國應該入鄉隨俗,你堵,我也堵!
BBR開始為網路添堵
永遠不要欺負老實人,BBR開始做損人不利己的事了。在中國,所有的TCP擁塞控制演算法都無法被公正評估,請注意,這個修改的意義在於,BBR對於自身的效能沒有任何提升,只是為了損人而已。我跑得慢,我踹你一腳把你整瘸了,你會更慢,這樣我就第一了,競速,競速而已!那麼,這件壞事如何來做呢?
我的第一個版本不公開,事實證明它更有效,起碼上了我的版本,別的就沒的跑了,但問題是上兩個我的版本,他倆雙胞胎也會打架打得頭破血流...本著和諧共存的原則,我從不教人學壞,所以我會刪除並忘掉程式碼,再不提起。我這裡給出稍微溫和點的版本,兄弟倆打架的情況依然存在,但不嚴重,問題是,如何區別對方是否是自家人...難!
BBR計算總的最大發送量的時候,不是按照max-Bandwidth和min-RTT的乘積計算的嗎?我這裡維護了一個最小RTT視窗內的max-RTT,只要在一個最小RTT視窗內的實際RTT不大於上一次的max-RTT,我就讓BBR使用這個實際的RTT而不是什麼最小的RTT。這裡的原則在於,BBR會嘗試在排隊不丟包的情況下也去主動排隊,入鄉隨俗。
程式碼非常簡單,先為BBR增加一個欄位,即max_rtt_us,與min_rtt_us相對,然後修改update RTT和calc CWND的邏輯:
1.修改bbr_update_min_rtt
/* Track min RTT seen in the min_rtt_win_sec filter window: */filter_expired = after(tcp_time_stamp, bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ);if (rs->rtt_us >= 0 && (rs->rtt_us <= bbr->min_rtt_us || filter_expired)) { bbr->min_rtt_us = rs->rtt_us; bbr->min_rtt_stamp = tcp_time_stamp; bbr->rtt_us = rs->rtt_us; if (filter_expired) bbr->max_rtt_us = rs->rtt_us;}bbr->rtt_us = bbr->min_rtt_us;if (!filter_expired && rs->rtt_us >= 0 && rs->rtt_us < bbr->max_rtt_us) { bbr->rtt_us = rs->rtt_us;}
2.修改bbr_target_cwnd
if (inet_csk(sk)->icsk_ca_state != TCP_CA_Open) w = (u64)bw * bbr->min_rtt_us;else w = (u64)bw * bbr->rtt_us;
----------------------------
最大RTT和最小RTT之差就是排隊延遲,充分利用這個排隊延遲去添堵是一件簡單的好事,但是如何去對抗AQM則是一件非常複雜的事,因為你並不知道AQM的行為。以上的討論均建立在尾部丟包的基礎之上,然而現實情況則要面臨複雜的AQM,在文章《 Linux Kernel 4.9中TCP BBR演算法的科普解釋》的“君莫舞,君不見玉環飛燕皆塵土”以及“BBR的優勢之-與AQM的關係”兩節中,我有闡述BBR如何樂觀地等待CUBIC之流被懲罰以及如何愉快地上位,然而在“廣中路上匝道”情形中,CUBIC並不會被懲罰,BBR自然也就不會上位,那怎麼辦,只能添堵,至於AQM怎麼處理,一視同仁吧。換句話說,BBR在CUBIC以及任意所謂“TCP加速者”面前,不必客氣,他們抽菸,你就放火。
快遞或者網路可靠嗎
現在人們沒了網際網路就不能生活,這也是一種錯覺。其實網際網路本身就是一種錯覺,它是一種不得已而為之的錯覺!
去年1月我去深圳永珍城(之所以說永珍城而不是人人樂,我是想說我買的東西有多麼高大上,以至於我多麼迫不及待地想擁有)買東西,無貨,咋辦?店主說次日可取,他們從廣州拿貨。現在問題來了,去一趟廣州難嗎?為什麼我自己不直接去廣州買,還要深圳永珍城去廣州拿貨後再賣給我?因為我沒時間!如果我有大把的時間又那麼喜歡那件物品,我肯定自己去廣州了,順帶旅遊,然而我缺的正是時間。
快遞業務填補了人們的時間間隙。但是快遞業務真的可靠嗎?
如果我自己去廣州拿貨,假設高鐵不脫軌,汽車不翻車,自己不被人捅的情況下,一路上我愉快地去,拿到貨後愉快地歸來,一路上我親自護送貨品,我放心,我踏實。如果交由快遞,我不知道快遞車會不會翻車,會不會被人搶,裡面會不會是假貨...一切我都不確定,在送到我手裡前,我只能禱告~!但好處在於,這段送貨的時間,在我信任快遞公司的前提下,我可以做別的工作,如果我不信任快遞公司,我只能心急如焚。好在,現在的快遞公司,特別是順豐還算靠譜,你不需要心急如焚。
但是網路,其可靠性完全是另一回事,幸虧人們用了TCP,不然就別玩了。位元組的複製往往比絲帛的織造更加廉價,所以TCP有一個儲存重發的機制,傳送資訊前先儲存資訊,一段時間沒有收到迴應,就重發被儲存的資訊,收到迴應則將資訊刪除,如果發了一批絲綢到遠方,一段時間沒有反饋,然後再去織一批新的,那代價可就大了去了...
----------------------------
我不親自去廣州而去委託快遞公司,正是因為我沒有時間,那麼如果快遞公司的快遞過程“彌補”了我本應該節省的時間(比如快遞員懶惰),我還不如自己去拿貨呢。
網路也一樣,如果網路的延遲太高,那還不如用U盤拷貝資訊,用汽車運輸U盤,然後交付呢...網路和快遞一樣,就是圖快,用專業的運輸代替你自己的自取。然而,如果網路中有Bufferbloat,那麼還不如去自取,甚至去用U盤拷貝。
Bufferbloat讓網路喪失了快速傳輸通道的名聲。
新的Bloat版本的BBR演算法
週日早晨,我登入到了溫州老闆提供的位於國外的VPS機器上,演繹了一個新版的BBR。也是添堵版的,在我的WIFI環境下碾壓了標準的BBR,這就好像魔人布歐的分身一樣,一個是好人的時候,另一個必須是惡棍。非常簡單:
1.為bbr增加一個minmax型別的max_rtt欄位
2.修改bbr_update_min_rtt函式
filter_expired = after(tcp_time_stamp, bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ);if (rs->rtt_us >= 0 && (rs->rtt_us <= bbr->min_rtt_us || filter_expired)) { bbr->min_rtt_us = rs->rtt_us; bbr->min_rtt_stamp = tcp_time_stamp; bbr->rtt_us = rs->rtt_us;}bbr->rtt_us = rs->rtt_us;rtt_prior = minmax_get(&bbr->max_rtt);// 迄今為止最大的RTT與當前RTT取其小!是不是拿最大RTT和最小RTT求個"平均"什麼的更合理呢?// 反正我是佔點Buffer空間bbr->rtt_us = min(bbr->rtt_us, rtt_prior);minmax_running_max(&bbr->max_rtt, bbr_bw_rtts, bbr->rtt_cnt, rs->rtt_us);
我祝願所有的TCP連線早日崩潰,我祝願網際網路越來越擁堵,最終不可用。
為什麼BBR是合理的
AIMD是基於丟包的擁塞控制演算法的根基,這必然會Buffer bloat,解決之道就是不採用基於丟包的演算法,而採用基於時延的演算法,但是....但是隻要有一個基於丟包的演算法還跑在網際網路上,那麼所有基於時延的演算法都會集體退讓...這是基於時延演算法弊端,既然它基於時延而不是丟包,那麼它就是註定要吃虧的。正確的做法是什麼?
BBR無視丟包(也並非絕對,BBR在處理非Open狀態時還是有措施的),無視時延(也非絕對,BBR只是無視了RTT的瞬時變化值),採用了實時採集並保留時間視窗的策略,這初看起來是吃虧的演算法,與基於時延的演算法無異,但是BBR擁有Probe More和Drain Less過程,這非常合理。
合理的並不意味著是可用的。我依然祝願所有的TCP連線早日崩潰,我祝願網際網路越來越擁堵,最終變得不可用。我有一個夢想,每個人掄起鐵錘去鍊鋼,少說多做,最好不說。