非常有意思的Flowlet
週五瞭解到一個叫做Flowlet的東西,比較有意思。大體上說來,它是由一個問題而引出的一個解決方案,由於理解還不夠深入,所以也暫時只能這麼說。
我先從問題說起。
ISP的動態負載均衡
由於公共骨幹網上流量的不確定性,每一條鏈路的負載不盡相同,為了保證總頻寬的最佳利用率,ISP往往會做一些動態負載均衡的策略。如下圖所示:
時刻1:
時刻2:
packet負載均衡和flow負載均衡
到底是按照packet做負載均衡呢還是按照一個五元組flow來做負載均衡呢?這是一個問題,很多人在做負載均衡的時候都會面臨這個選擇問題。
具體來講,如果一條flow是強序的,那麼基於packet的負載均衡將會導致亂序,這是裝置在做負載均衡時要避免的,比如TCP就不能基於packet來做負載均衡,而對於UDP這種協議便可以。
目前從主機到中間裝置,幾乎所有的從板卡,網路卡佇列,到CPU中斷,到hash演算法,均有機制保證TCP的強序性。
TCP的問題
正是由於TCP是強序的,所以TCP便無法基於packet做負載均衡,也就意味著,只要一條TCP流已經發起了,它就幾乎不能再改變底層鏈路了,至少是最好不要改變底層鏈路,因為一旦底層鏈路改變,TCP將增加面臨亂序的概率。
幸虧TCP是burst傳送
前面我的描述其實隱含了一個假設,即TCP flow的packet是平滑傳送的:
然而實際上,不管是實際抓包(你可以觀測抓包的tcptrace圖)還是從具體實現(你可以看30年內任何TCP實現的原始碼,比如cubic,vegas…)上看,你會發現TCP packet的傳送其實是burst的:
哈哈,可乘之機!看到兩批次burst之間的時間間隙沒有,在這種間隙足夠大的時候切換下層鏈路是一個好的時機。這意味著舊鏈路上的packet均已經離開了鏈路或者至少將要離開鏈路,這個時候切換鏈路將不會造成亂序,不會破壞TCP的強序要求。
嗯,這就是Flowlet。
Flowlet
一般而言,英文中的“-let”字尾代表“微小”的意思,比如booklet,houselet,以及Java applet…一個Flowlet代表的就是一條小流。如下圖所示:
在巨集觀的觀感上,可以把一條flow看成是多個flowlet組成的,負載均衡現在就是基於flowlet來進行了,好吧,又引入了一箇中間層,它既不是packet,也不是flow,而是大於packet小於flow的flowlet,哈哈,很有意思!
那麼到底如何定量的去切分flowlet呢?這裡給出一個公式:
BBR之後一切將不再
我個人覺得flowlet的理念非常Q,perfect,通過一個新的層次解決了強序flow的負載均衡問題。然而它借用了一個TCP實現上的問題或者說是bug,即burst機制。所謂藉著壞事幹好事。
在TCP的AIMD模型下,pacing傳送幾乎是不可能的,因為pacing的計算會破壞AIMD的盲決策,最終的控制模型將會畸變。然而近期Google的研究證明簡單的AIMD用於TCP傳輸其實是錯誤的,而引入了一中新的BBR pacing傳輸模型,這個BBR一下子把TCP擁塞控制演算法引入了2.0時代!
我想表達什麼?
在BBR pacing模型下,我們假設BBR已經完美升級到了它應該成為的樣子,解決了一系列的失速,誤判等問題,屆時TCP packet的傳送將會是下面的樣子:
你可能再也捕捉不到那個flowlet中的
但BBR最終至多隻是終結了flowlet在TCP上的具體實現,它無法終結flowlet的理念。擁塞控制和負載均衡是兩個不同的領域,雖然有所關聯但卻井水不犯河水,擁塞控制說的是,當發現擁塞,要怎麼做,負載均衡說的是,它可以幫忙分擔擁塞。
Linux RFS中的影子
上週寫的那篇:
合併N個有序連結串列與FQ公平排程:https://blog.csdn.net/dog250/article/details/80234049
我找到了一道面試題或者說作業題在Linux中的影子,在我第一次聽聞flowlet的昨天,我想Linux RPS/RFS也有該理念的實現,具體看下面這段程式碼:
/*
* If the desired CPU (where last recvmsg was done) is
* different from current CPU (one in the rx-queue flow
* table entry), switch if one of the following holds:
* ...
* - The current CPU's queue tail has advanced beyond the
* last packet that was enqueued using this table entry.
* This guarantees that all previous packets for the flow
* have been dequeued, thus preserving in order delivery.
*/
if (unlikely(tcpu != next_cpu) &&
(...
((int)(per_cpu(softnet_data, tcpu).input_queue_head -
rflow->last_qtail)) >= 0)) {
tcpu = next_cpu;
rflow = set_rps_cpu(dev, skb, rflow, next_cpu);
}
後記
非常感激總是有人幫助我讓我重新思考技術的本質!今天週六一覺睡到8點半,所以這篇文章到了10點多才分享出來,遲來了,但總比沒有好。
對flowlet理解不深,不到一日而已,如果有需要討論的,或者說發現我的說法有錯誤的,希望能及時指出,我會及時回覆。
上午積累了很多的家務事,申請了延後執行,這快到中午了,估計也幹不完了,瘋子大人和小小馬上也就回來了,等待接受批評,但能總結出這篇文章,也算欣慰了。
相關文章
- 前端非常有意思的小技巧前端
- 一次非常有意思的SQL最佳化經歷:從30248.271s到0.001sSQL
- 有意思、有趣的文字
- 有意思的clip-path
- 兩個有意思的專案
- codeforces 1438D,思路非常非常巧妙的構造題
- 非常草包的決定
- 非常便捷的本地MockMock
- 有意思、好用的免費API分享API
- MYSQL 主鍵的那些 “有意思” 故事MySql
- 分享一個有意思的錯誤
- 有意思!強大的 SVG 濾鏡SVG
- 免費有意思的好用API推薦API
- 有意思的滑鼠指標互動探究指標
- 分享幾個有意思的陣列方法陣列
- 一個有意思的數學東西
- 有意思的JSON.parse()、JSON.stringify()JSON
- 一份很有意思的 GC logGC
- 有意思的前端函式面試題前端函式面試題
- 非常全的VsCode快捷鍵VSCode
- 一個有意思的CSS圖片hover效果CSS
- 一個很有意思的選擇表情DialogActivity
- React Suite 做了一個有意思的決定ReactUI
- 拿Proxy可以做哪些有意思的事兒
- 拿 Proxy 可以做哪些有意思的事兒
- 非常棒的電音資源
- IceWM:一個非常酷的桌面
- Python 庫這非常的實用Python
- Maven那些非常有用的 PluginMavenPlugin
- kill 程式時遇到的一件有意思的事情
- 有意思、好用、熱門的免費API推薦API
- 漲姿勢了,有意思的氣泡 Loading 效果
- 記一次有意思的種樹比賽
- 一個有意思且有用的手法——關閉ping
- 一個很有意思的hook庫:react-hangerHookReact
- 非常有趣的Python的用法彙總Python
- 4個非常有用的 Flutter 技巧Flutter
- 非常實用的站點收錄