TCP會被UDP取代麼?

安全劍客發表於2020-02-04
為什麼這麼設計(Why's THE Design)是一系列關於計算機領域中程式設計決策的一個具體的問題並從不同的角度討論這種設計的優缺點、對具體實現造成的影響。

TCP會被UDP取代麼?TCP會被UDP取代麼?
TCP 協議可以說是今天網際網路的基石,作為可靠的傳輸協議,在今天幾乎所有的資料都會通過 TCP 協議傳輸,然而 TCP 在設計之初沒有考慮到現今複雜的網路環境,當你在地鐵上或者火車上被斷斷續續的網路折磨時,你可能都不知道這一切可能都是 TCP 協議造成的。本文會分析 TCP 協議為什麼在弱網環境下有嚴重的效能問題。

底層的資料傳輸協議在設計時必須要對頻寬的利用率和通訊延遲進行權衡和取捨,所以想要解決實際生產中的全部問題是不可能的,TCP 選擇了充分利用頻寬,為流量而設計,期望在儘可能短的時間內傳輸更多的資料。

在網路通訊中,從傳送方發出資料開始到收到來自接收方的確認的時間被叫做往返時延(Round-Trip Time,RTT)。

弱網環境是丟包率較高的特殊場景,TCP 在類似場景中的表現很差,當 RTT 為 30ms 時,一旦丟包率達到了 2%,TCP 的吞吐量就會下降 89.9%[^3],從下面的表中我們可以看出丟包對 TCP 的吞吐量極其顯著的影響:

TCP會被UDP取代麼?TCP會被UDP取代麼?
本文將分析在弱網環境下(丟包率高)影響 TCP 效能的三個原因:

TCP 的擁塞控制演算法會在丟包時主動降低吞吐量;

TCP 的三次握手增加了資料傳輸的延遲和額外開銷;

TCP 的累計應答機制導致了資料段的傳輸;

在上述的三個原因中,擁塞控制演算法是導致 TCP 在弱網環境下有著較差表現的首要原因,三次握手和累計應答兩者的影響依次遞減,但是也加劇了 TCP 的效能問題。

擁塞控制

TCP 擁塞控制演算法是網際網路上主要的擁塞控制措施,它使用一套基於線増積減(Additive increase/multiplicative decrease,AIMD)的網路擁塞控制方法來控制擁塞[^4],也是造成 TCP 效能問題的主要原因。

第一次發現的網際網路擁塞崩潰是在 1986 年,NSFnet 階段一的骨幹網的處理能力從 32,000bit/s 降到了 40bit/s,該骨幹網的處理能力直到 1987 和 1988 年,TCP 協議實現了擁塞控制之後才得到解決。正是因為發生過網路阻塞造成的崩潰,所以 TCP 的擁塞控制演算法就認為只要發生了丟包當前網路就發生了擁堵,從這一假設出發,TCP 就使用了慢啟動和線增積減的機制實現擁塞控制。

TCP會被UDP取代麼?TCP會被UDP取代麼?

每一個 TCP 連線都會維護一個擁塞控制視窗(Congestion Window),擁塞控制視窗的作用有兩個:

1.防止傳送方向接收方傳送了太多資料,導致接收方無法處理;
2.防止 TCP 連線的任意一方向網路中傳送大量資料,導致網路擁塞崩潰;
除了擁塞視窗大小(cwnd)之外,TCP 連線的雙方都有接收視窗大小(rwnd),在 TCP 連線建立之初,傳送方和接收方都不清楚對方的接收視窗大小,所以通訊雙方需要一套動態的估算機制改變資料傳輸的速度,在 TCP 三次握手期間,通訊雙方會通過 ACK 訊息通知對方自己的接收視窗大小,接收視窗大小一般是頻寬延遲乘積(Bandwidth-delay product, BDP)決定的,不過在這裡我們就不展開介紹了。

客戶端能夠同時傳輸的最大資料段的數量是接收視窗大小和擁塞視窗大小的最小值,即 min(rwnd, cwnd)。TCP 連線的初始擁塞視窗大小是一個比較小的值,在  Linux 中是由 TCP_INIT_CWND 定義的:

 /* TCP initial congestion window as per rfc6928 */ 
#define TCP_INIT_CWND       10

初始擁塞控制視窗的大小從出現之後被多次修改,幾個名為 Increasing TCP's Initial Window 的 RFC 文件:RFC2414、RFC3390和 RFC6928 分別增加了 initcwnd 的值以適應不斷提高的網路傳輸速度和頻寬。

TCP會被UDP取代麼?TCP會被UDP取代麼?

如上圖所示,TCP 連線傳送方的擁塞控制視窗大小會根據接收方的響應而變化:

1.線性增長:經過 1 個 RTT ,擁塞視窗大小會加一;
2.積式減少:當傳送方傳送的資料包丟包時,慢啟動閾值會減半;
如果 TCP 連線剛剛建立,由於 Linux 系統的預設設定,客戶端能夠同時傳送 10 個資料段,假設我們網路的頻寬是 10M,RTT 是 40ms,每個資料段的大小是 1460 位元組,那麼使用 BDP 計算的通訊雙方視窗大小上限應該是 35,這樣才能充分利用網路的頻寬:

然而擁塞控制視窗的大小從 10 漲到 35 需要 2RTT 的時間,具體的過程如下:

1.傳送方向接收方傳送 initcwnd = 10 個資料段(消耗 0.5RTT);
2.接收方接收到 10 個資料段後向傳送方傳送 ACK(消耗 0.5RTT);
3.傳送方接收到傳送方的 ACK,擁塞控制視窗大小由於 10 個資料段的成功傳送 +10,當前擁塞控制視窗大小達到 20;
4.傳送方向接收方傳送 20 個資料段(消耗 0.5RTT);
5.接收方接收到 20 個資料段後向傳送方傳送 ACK(消耗 0.5RTT);
6.傳送方接收到傳送方的 ACK,擁塞控制視窗大小由於 20 個資料段的成功傳送 +20,當前擁塞控制視窗大小達到 40;
從 TCP 三次握手建立連線到擁塞控制視窗大小達到假定網路狀況的最大值 35 需要 3.5RTT 的時間,即 140ms,這是一個比較長的時間了。

早期網際網路的大多數計算裝置都通過有線網路連線,出現網路不穩定的可能性也比較低,所以 TCP 協議的設計者認為丟包意味著網路出現擁塞,一旦發生丟包,客戶端瘋狂重試就可能導致網際網路的擁塞崩潰,所以發明了擁塞控制演算法來解決該問題。

但是如今的網路環境更加複雜,無線網路的引入導致部分場景下的網路不穩定成了常態,所以丟包並不一定意味著網路擁堵,如果使用更加激進的策略傳輸資料,在一些場景下會得到更好的效果。

三次握手

TCP 使用三次握手建立連線應該是全世界所有工程師都十分了解的知識點,三次握手的主要目的是避免歷史錯誤連線的建立並讓通訊的雙方確定初始序列號,然而三次握手的成本相當高,在不丟包的情況下,它需要建立 TCP 連線的雙方進行三次通訊。

TCP會被UDP取代麼?TCP會被UDP取代麼?

如果我們要從北京訪問上海的伺服器,由於北京到上海的直線距離約為 1000 多公里,而光速是目前通訊速度的極限,所以 RTT 一定會大於 6.7ms:

然而因為光在光纖中不是直線傳播的,真正的傳輸速度會比光速慢 ~31%,而且資料需要在各種網路裝置之間來回跳轉,所以很難達到理論的極限值。在生產環境中從北京到上海的 RTT 大概在 40ms 左右,所以 TCP 建立連線所需要最短時間也需要 60ms(1.5RTT)。

在網路環境較差的地鐵、車站等場景中,因為丟包率較高,客戶端很難與服務端快速完成三次通訊並建立 TCP 連線。當客戶端長時間沒有收到服務端的響應時,只能不斷髮起重試,隨著請求次數逐漸增加,訪問的延遲也會越來越高。

由於大多數的 HTTP 請求都不會攜帶大量的資料,未被壓縮的請求和響應頭大小在 ~200B 到 2KB 左右,而 TCP 三次握手帶來的額外開銷是 222 位元組,其中乙太網資料幀佔 3 * 14 = 42位元組,IP 資料幀佔 3 * 20 = 60 位元組,TCP 資料幀佔 120 位元組:

TCP會被UDP取代麼?TCP會被UDP取代麼?

雖然 TCP 不會為每一個發出的資料段建立連線,但是三次握手建立連線需要的成本還是相當高,不僅需要額外增加 1.5RTT 的網路延時,還需要增加 222 位元組的額外開銷,所以在弱網環境下,通過三次握手建立連線會加劇 TCP 的效能問題。

重傳機制

TCP 傳輸的可靠性是通過序列號和接收方的 ACK 來保證的,當 TCP 傳輸一個資料段時,它會將該資料段的副本放到重傳佇列上並開啟計時器:

如果傳送方收到了該資料段對應的 ACK 響應,當前資料段就會從重傳佇列中刪除;
如果傳送方在計時器到期之間都沒有收到該資料段對應的 ACK,就會重新傳送當前資料段;
TCP 的 ACK 機制可能會導致傳送方重新傳輸接收方已經收到了資料段。TCP 中的 ACK 訊息表示該訊息之前的全部訊息都已經被成功接收和處理,例如:

傳送方向接收方傳送了序號為 1-10 的訊息;
接收方向傳送方傳送 ACK 8 響應;
傳送方認為序號為 1-8 的訊息已經被成功接收;
這種 ACK 的方式在實現上比較簡單,更容易保證訊息的順序性,但是在以下情況可能會導致傳送方重傳已經接收的資料:
TCP會被UDP取代麼?TCP會被UDP取代麼?

如上圖所示,接收方已經收到了序號為 2-5 的資料,但是由於 TCP ACK 的語義是當前資料段前的全部資料段都已經被接收和處理,所以接收方無法傳送 ACK 訊息,由於傳送方沒有收到 ACK,所有資料段對應的計時器就會超時並重新傳輸資料。在丟包較為嚴重的網路下,這種重傳機制會造成大量的頻寬浪費。

總結

TCP 協議的一些設計在今天來看雖然仍然具有巨大的價值,但是並不能適用於所有場景。為了解決 TCP 的效能問題,目前業界有兩種解決方案:

1.使用 UDP 構建效能更加優異、更靈活的傳輸協議,例如:QUIC 等;
2.通過不同的手段優化 TCP 協議的效能,例如:選擇性 ACK(Selective ACK, SACK)[^16],TCP 快開啟(TCP Fast Open, TFO);
由於 TCP 協議在作業系統核心中,不利於協議的更新,所以第一種方案目前發展的更好,HTTP/3 就使用了 QUIC 作為傳輸協議。我們在這裡重新回顧一下導致 TCP 效能問題的三個重要原因:

TCP 的擁塞控制在發生丟包時會進行退讓,減少能夠傳送的資料段數量,但是丟包並不一定意味著網路擁塞,更多的可能是網路狀況較差;
TCP 的三次握手帶來了額外開銷,這些開銷不只包括需要傳輸更多的資料,還增加了首次傳輸資料的網路延遲;
TCP 的重傳機制在資料包丟失時可能會重新傳輸已經成功接收的資料段,造成頻寬的浪費;
TCP 協議作為網際網路資料傳輸的基石可以說是當之無愧,雖然它確實在應對特殊場景時有些問題,但是它的設計思想有著非常多的借鑑意義並值得我們學習。

到最後,我們還是來看一些比較開放的相關問題,有興趣的讀者可以仔細思考一下下面的問題:

QUIC 協議是能否保證丟包率較高時的傳輸效能?
除了 SACK 和 TFO 之外還有哪些手段可以優化 TCP 的效能?

原文地址: https://www.linuxprobe.com/tcp-udp.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2674468/,如需轉載,請註明出處,否則將追究法律責任。

相關文章