深度思考|TCP協(xié)議存在那些缺陷?

TCP如何優(yōu)化吞吐率,我很直接說優(yōu)化不了,這讓我甩開了很多令人尷尬的麻煩事兒。但我可以聊一聊。
為什么優(yōu)化不了?因?yàn)榛瑒?dòng)窗口。
當(dāng)我這么說時(shí),有人不由分說就懟,說“如果是cwnd limited”呢?我要表達(dá)的是,cwnd limited原因有二,如果你的cc算準(zhǔn)了,那就是網(wǎng)絡(luò)原本就是擁塞的,如果你的cc沒算準(zhǔn),那是你的cc的問題,換句話說,cwnd決定的是你TCP連接吞吐的下限,卻不限制其上限。
為什么因?yàn)榛瑒?dòng)窗口?因?yàn)榛瑒?dòng)窗口本質(zhì)上是一個(gè)“停-等”策略。
“停-等”怎么了?因?yàn)橐龋砸?,一停就慢?也叫HoL阻塞)。
隊(duì)頭阻塞(英語:Head-of-line blocking,縮寫:HOL blocking)在計(jì)算機(jī)網(wǎng)絡(luò)的范疇中是一種性能受限的現(xiàn)象。它的原因是一列的第一個(gè)數(shù)據(jù)包(隊(duì)頭)受阻而導(dǎo)致整列數(shù)據(jù)包受阻。例如它有可能在緩存式輸入的交換機(jī)中出現(xiàn),有可能因?yàn)閭鬏旐樞蝈e(cuò)亂而出現(xiàn),亦有可能在HTTP流水線中有多個(gè)請求的情況下出現(xiàn)。
等什么?等buffer被填滿。
什么buffer?就是接收窗口。
等接收窗口被填滿有什么問題嗎?問題就在這里!
那么要取消滑動(dòng)窗口嗎?這個(gè)最后再談。先說本質(zhì)問題。
問題在于,這塊作為滑動(dòng)窗口的buffer有一個(gè)約束,要求其中的字節(jié)序列號(hào)必須連續(xù)。這意味著這個(gè)buffer便不再是一塊無差別隨機(jī)訪問的內(nèi)存了,而變成了一個(gè)隊(duì)列。一旦出現(xiàn)一個(gè)hole,傳輸過程就必須停下來等待它被填充,期間窗口的滑動(dòng)是被阻滯。
當(dāng)我這么說時(shí),有人不由分說就懟,說“流量控制是對所有有連接協(xié)議的基本要求,滑動(dòng)窗口就是為了流控存在的”。我表達(dá)的意思是,首先,當(dāng)出現(xiàn)hole并在它被補(bǔ)齊前,TCP擁塞狀態(tài)機(jī)完全接管cwnd的計(jì)算,cc將不起作用,此時(shí)要么你的連接成為rwnd limited,要么帶寬估計(jì)失真,誆論高吞吐,其次,滑動(dòng)窗口并非流量控制的唯一方式。
誕生于1970~1980年代的TCP從來就不是為性能而生的。當(dāng)人們意識(shí)到性能問題的時(shí)候,隨即就出現(xiàn)了依賴out-of-order queue的selective ACK。但于本質(zhì)問題無補(bǔ),基因決定了上限。
設(shè)計(jì)傳輸協(xié)議,肯定要把端到端語義和傳輸語義分開,不然還要什么分層模型。簡單說,傳輸只關(guān)注數(shù)據(jù)包看不見序列號(hào),端到端只重排字節(jié)看不見數(shù)據(jù)包。這需要在字節(jié)流的序列號(hào)空間和數(shù)據(jù)包之間做一次映射。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。∏?00名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?


問題在于,致使TCP沒有作出這種設(shè)計(jì)的根源是什么?
在于它的“流式設(shè)計(jì)”。下面的鏈接可以找到故事的一部分:
Transmission Control Protocol (TCP) 1973-1976
分歧在于拆包和組裝,為了讓分組交換站在電路交換的對面,重新組裝由端到端負(fù)責(zé),這就不強(qiáng)求TCP流經(jīng)過相同路由器了,但這個(gè)策略未竟全功。
未竟全功,核心原因是TCP協(xié)議被設(shè)計(jì)的時(shí)候并沒有承載TCP數(shù)據(jù)的“數(shù)據(jù)報(bào)協(xié)議分組”,這是一個(gè)先有雞先有蛋的問題,在1973年~1976年,IP尚未從TCP中分離出來,所以IP無法承載TCP,更別提UDP了。UDP是當(dāng)IP從TCP中分離出來后,作為IP協(xié)議的等價(jià)語義在TCP層的補(bǔ)充而被后來添加的。
那么TCP只能自己承載自己,直接在分組交換網(wǎng)傳輸。
允許亂序是分組交換的基本特征之一,TCP協(xié)議也因此將保序邏輯放在了端到端,然而對于傳輸邏輯,TCP依然更像一條虛電路流,而不像數(shù)據(jù)報(bào)分組。
這是TCP后續(xù)停-等buffer,GBN低效的根源。為什么呢?
整個(gè)傳輸邏輯的實(shí)體不是TCP數(shù)據(jù)包,而是沒有邊界的TCP字節(jié)流。換句話說,發(fā)送端一次發(fā)送1000字節(jié)的數(shù)據(jù),到了接收端,可能收到2個(gè)數(shù)據(jù)包,一個(gè)20字節(jié),另一個(gè)980字節(jié),也可能收到1000個(gè)數(shù)據(jù)包,每一個(gè)1字節(jié),當(dāng)然,更大可能是依然是一個(gè)1000字節(jié)的數(shù)據(jù)包。無論如何,接收端無法“基于數(shù)據(jù)包做ACK,只能對字節(jié)做ACK”,但主機(jī)處理處理依然以數(shù)據(jù)包為單位。這逆轉(zhuǎn)了人們設(shè)計(jì)協(xié)議時(shí)對時(shí)間和空間做trade-off時(shí)的偏好
對空間的關(guān)注超過了對吞吐的關(guān)注。為每一個(gè)字節(jié)安排一個(gè)ACK,將使TCP協(xié)議頭變得冗長到不可接受,這不僅不能帶來吞吐的提升,還會(huì)消耗大量的帶寬用于ACK本身的管理開銷。
摒棄數(shù)據(jù)包的概念,直接對TCP的字節(jié)流對積累ACK可以解決上述問題。積累ACK自然而然就等價(jià)于滑動(dòng)窗口和GBN了。
整個(gè)故事是,流式抽象導(dǎo)致了必須基于字節(jié)進(jìn)行ACK,進(jìn)而積累確認(rèn)和GBN重傳被認(rèn)為是性價(jià)比最高的。這是一個(gè)很低效的設(shè)計(jì),但管用。
selective ACK是一種向正確方式的回歸,但依然沒能擺脫“基于字節(jié)ACK”的夢魘,SACK看上去很別扭并勉強(qiáng),因?yàn)樗坏貌晃赥CP Option中,空間受限而不能求全,本質(zhì)原因還是最初的那個(gè),如果給SACK安排了不受限制的空間,ACK報(bào)文將變得冗長。
我簡單畫了一個(gè)TCP本應(yīng)該在分組交換網(wǎng)中的正確姿勢:

非常清晰的兩層結(jié)構(gòu)。接收窗口限制了可用buffer的大小,而buffer只有夠不夠的問題,如果空間不足,顯式發(fā)送抑制消息給ACK邏輯即可,ACK將抑制消息反饋到源端。
與buffer的解釋類似,網(wǎng)絡(luò)傳輸只有帶寬滿不滿,擁塞與否的問題,而這些完全通過congestion control,pacing邏輯等完成,令牌桶里完全序列號(hào)的概念。
端到端語義和傳輸語義分離的好處不勝枚舉:
很容易統(tǒng)計(jì)重傳率指標(biāo),需要傳輸?shù)淖止?jié)在端到端子層,實(shí)際傳輸?shù)淖止?jié)在傳輸子層。
網(wǎng)絡(luò)傳輸可以肆意并行,無需關(guān)注亂序,重組等問題,以最大化帶寬利用率為目標(biāo)。
確認(rèn)數(shù)據(jù)包而不是確認(rèn)字節(jié),靈活實(shí)現(xiàn)積累ACK或selective ACK,ACK報(bào)文可壓縮,可編碼。
...
簡單展示一個(gè)ACK報(bào)文的樣子:

現(xiàn)在看在新的設(shè)計(jì)下,滑動(dòng)窗口本身的問題。要不要取消它?滑動(dòng)窗口要取消,問題在于,首先,如何做流量控制,其次,流量控制如何使用buffer。
第一個(gè)問題很容易:
buffer是標(biāo)量而非矢量,只看大小不看方向,只要尚未超過最大使用限額,就可以收數(shù)據(jù)。
設(shè)置可用buffer最大值以及最大允許的突發(fā),超過限額即發(fā)送源抑制。
看第二個(gè)問題。如果buffer中數(shù)據(jù)有hole不連續(xù),應(yīng)用程序如何收走數(shù)據(jù)?如果數(shù)據(jù)一直不被收走,buffer總會(huì)沒有空閑空間。這不是又回到問題的原點(diǎn)了嗎?問題的解決在于使用buffer的方式。
不同于標(biāo)準(zhǔn)TCP一個(gè)連接獨(dú)占buffer的方式:

新的設(shè)計(jì)采用子連接復(fù)用的方式讓多個(gè)連接共享同一個(gè)buffer:

buffer粒度更細(xì),施展空間更大,同一子連接HoL阻塞概率更低。
QUIC大概就是這個(gè)意思吧。
...
我不認(rèn)同NAK的原因還是因?yàn)樗鼤?huì)引入紛亂的誤判。
...
現(xiàn)在,可以把上面的設(shè)計(jì)部署在IDC網(wǎng)絡(luò)(互聯(lián)網(wǎng)數(shù)據(jù)中心(Internet Data Center), 簡稱IDC)使用流體滲透原理去對抗incast,也可以部署在MPTCP邏輯通道上。
MultiPath TCP(MPTCP)由互聯(lián)網(wǎng)工程任務(wù)組(IETF)MultiPath TCP工作組研發(fā),其目的是允許傳輸控制協(xié)議Transmission Control Protocol(TCP)連接使用多個(gè)路徑來最大化信道資源使用。
摩爾定律 在40年中持續(xù)改變甚至逆轉(zhuǎn)人們的關(guān)注點(diǎn),30年前,顯卡,網(wǎng)卡被稱為CPU的外設(shè),如今CPU成了GPU,SmartNIC的外設(shè)。同理,TCP剛出來的時(shí)候,內(nèi)存昂貴,帶寬昂貴,于是人們擠壓空間而不在乎時(shí)間,GBN順勢而為,TCP頭也就成了那個(gè)樣子,現(xiàn)在看來各種不夠,大并發(fā)場景經(jīng)常遭遇bind占CPU高的問題根源就是端口號(hào)只有16bits,TLV不是更好嗎?可是那個(gè)時(shí)代不允許啊。直到空間不再昂貴,人們開始?jí)嚎s時(shí)間,吞吐性能問題就擺在眼前,可是TCP已經(jīng)是那個(gè)樣子了,它就是為空間優(yōu)化而生的,還能怎么辦?我總說TCP是一個(gè)過時(shí)的老協(xié)議,言外之意就是說要用新的傳輸協(xié)議了,比如QUIC,或者比QUIC更好的協(xié)議。TCP優(yōu)化?到頭了。追求陸地速度就去坐高鐵,而不是坐高性能綠皮車。
