TCP 效能優化淺析

mogic發表於2018-02-02

前言

TCP 作為一種最常用的傳輸層協議,它的作用是在不可靠的傳輸通道上,提供可靠地資料傳輸。在各層網路協議中,只要有一層協議是可靠的,那麼整個網路傳輸就是安全可靠的。現實中,幾乎所有的 HTTP 流量都是經過 TCP 傳輸。因此,我們要進行 web 效能優化,TCP 是其中的關鍵一環。要針對 TCP 進行效能優化,就得理解其工作原理。

三次握手

眾所周知,建立一次 TCP 連線需要進行三次握手。關於三次握手,一圖勝千言。

圖1

三次握手給 TCP 帶來了很大的延遲,不過這個握手過程是必不可少的。因為如果沒有三次握手,有可能會出現一些已經失效的請求包突然又傳到服務端,服務端認為這是客戶端發起的一次新的連線,於是發出確認包,表示同意建立連線。而客戶端並不會有響應,導致伺服器出現空等,白白浪費伺服器資源。

既然三次握手的過程不可避免,那麼我們只能通過重用 TCP 連線,減少三次握手的次數。HTTP 1.1 引入了長連線,通過在請求頭中加入 Connection: keep-alive, 來告訴請求響應完畢後,不要關閉連線。不過 HTTP 長連線也是有限制的,伺服器通常會設定 keep-alive 超時時間和最大請求數,如果請求超時或者超過最大請求數,伺服器會主動關閉連線。

除此之外,TFO(TCP Fast Open,TCP 快速開啟)這種機制也被設計用於優化三次握手過程。它通過握手開始時的 SYN 包中的 TFO cookie(一個 TCP 選項)來驗證一個之前連線過的客戶端。如果驗證成功,它可以在三次握手最終的 ACK 包收到之前就開始傳送資料。

圖2

Linux 3.7 及以後的核心在客戶端及伺服器中支援 TFO, 對於移動端,Android 和 iOS 9+ 都支援 TFO,不過 iOS 並未預設啟用。

PS: 推薦大裝潢一個 wireshark,可以非常直觀的觀察到三次握手的過程。

螢幕快照 2018-02-02 下午11.30.33.png

流量控制

流量控制是一種預防傳送端向接受端傳送過多資料的機制。它的主要目的是為了防止接收端服務過載,從而出現丟包。為了實現流量控制,TCP 連線的每一方都要宣告自己的通告視窗(rwnd),表示自己的緩衝區最多能接收多少資料。如果其中一端跟不上對方的傳送速度,就通知對方一個較小的視窗。如果視窗大小為 0,應用層必須先清空緩衝區,才能繼續接收資料。這就是所謂的滑動視窗協議。

大家可能經常遇到這種情況,自己明明是百兆寬頻,實際下載速度每秒卻只有幾M。這種情況有可能就是通告視窗(rwnd)設定的不合理造成的。最初的 TCP 規範分配給接收視窗大小的欄位是 16 位,也就是 64KB(2 的 16 次方)。實際上,rwnd 的大小應該由 BDP(頻寬延遲積) 而定。BDP(bit) = bandwidth(b/s) * round-trip time(s)。比如一個 100Mbps 的寬頻,RTT 是100 ms,那麼 BDP = (100 / 8) * 0.1 = 1.25M。此時,要想提高網路傳輸吞吐量,rwnd 應該為 1.25 M。

為了解決這個問題,TCP 視窗縮放(TCP Window Scaling)出現了,它將視窗大小由 16 位擴充套件到 32 位。Linux 上自帶了緩衝大小調優機制,如下命令,可以檢視 Linux 初始視窗大小:

sysctl net.ipv4.tcp_rmem
// 輸出 net.ipv4.tcp_rmem = 4096	87380    6291456
// 從左到右一次為最小值、預設值、最大值
複製程式碼

慢啟動

流量控制機制可以防止傳送端和接收端之間的服務過載,但無法防止任何一端向某個網路的傳送資料過載,因此還需要一個估算機制,根據網路環境動態改變資料傳輸速度,這就是慢啟動出現的原因。

慢啟動為傳送方的 TCP 增加了一個視窗:擁塞視窗(congestion window),記為 cwnd。當與另一個網路的主機建立 TCP 連線時,cwnd 初始化為 1 個 TCP 段。每收到一個 ACK,cwnd 就增加一個 TCP 段。傳送端取 cwnd 和 rwnd 中的最小值作為傳送上限。可以這樣理解,擁塞視窗是傳送端使用的流量控制,而通告視窗是接收端使用的流量控制。

一開始 cwnd 為 1,傳送方只傳送一個 mss(最大報文段長度) 大小的資料包,收到 ack 後,cwnd 加 1,cwnd=2。

此時 cwnd 2,則傳送方要傳送兩個 mss 大小的資料包,傳送方會收到兩個 ack,則 cwnd 會進行兩次加一的操作,則也就是 cwnd+2,則 cwnd=4,也就是 cwnd = cwnd*2。

以此類推,每次 rtt 後,cwnd 都會變成上次傳送前的 2 倍。因此,cwnd 的大小是呈指數級在遞增。

圖3

隨著 cwnd 的增加,會傳送網路過載,此時會出現丟包。一旦發現有這種問題,cwnd 會成倍減少。

圖4

為了減少往返次數,初始擁塞視窗的大小設定就尤為重要。預設情況下(RFC 2581),初始 cwnd 為 4 個 MSS。Google 建議將初始視窗改為 10 個 MSS。根據 Google 的研究,90% 的 HTTP 請求資料都在 16KB 以內,約為 10 個 MSS。

總結

本文介紹了 TCP 的部分工作原理,包括三次握手、流量控制、慢啟動,並闡述了 TCP 快速開啟、視窗縮放、增加初始擁塞視窗大小等優化手段。內容有點偏理論,還是需要多多實踐,才能合理掌握各種優化手段。


參考文獻:

  1. 《Web效能權威指南》
  2. 《TCP/IP詳解,卷1:協議》
  3. 淺談TCP優化
  4. TCP慢啟動中cwnd的增長問題? - one no的回答 - 知乎

相關文章