TCP 做爲一種最經常使用的傳輸層協議,它的做用是在不可靠的傳輸信道上,提供可靠地數據傳輸。在各層網絡協議中,只要有一層協議是可靠的,那麼整個網絡傳輸就是安全可靠的。現實中,幾乎全部的 HTTP 流量都是通過 TCP 傳輸。所以,咱們要進行 web 性能優化,TCP 是其中的關鍵一環。要針對 TCP 進行性能優化,就得理解其工做原理。web
衆所周知,創建一次 TCP 鏈接須要進行三次握手。關於三次握手,一圖勝千言。安全
三次握手給 TCP 帶來了很大的延遲,不過這個握手過程是必不可少的。由於若是沒有三次握手,有可能會出現一些已經失效的請求包忽然又傳到服務端,服務端認爲這是客戶端發起的一次新的鏈接,因而發出確認包,表示贊成創建鏈接。而客戶端並不會有響應,致使服務器出現空等,白白浪費服務器資源。性能優化
既然三次握手的過程不可避免,那麼咱們只能經過重用 TCP 鏈接,減小三次握手的次數。HTTP 1.1 引入了長鏈接,經過在請求頭中加入 Connection: keep-alive, 來告訴請求響應完畢後,不要關閉鏈接。不過 HTTP 長鏈接也是有限制的,服務器一般會設置 keep-alive 超時時間和最大請求數,若是請求超時或者超過最大請求數,服務器會主動關閉鏈接。bash
除此以外,TFO(TCP Fast Open,TCP 快速打開)這種機制也被設計用於優化三次握手過程。它經過握手開始時的 SYN 包中的 TFO cookie(一個 TCP 選項)來驗證一個以前鏈接過的客戶端。若是驗證成功,它能夠在三次握手最終的 ACK 包收到以前就開始發送數據。 服務器
Linux 3.7 及之後的內核在客戶端及服務器中支持 TFO, 對於移動端,Android 和 iOS 9+ 都支持 TFO,不過 iOS 並未默認啓用。cookie
PS: 推薦你們裝一個 wireshark,能夠很是直觀的觀察到三次握手的過程。 網絡
流量控制是一種預防發送端向接受端發送過多數據的機制。它的主要目的是爲了防止接收端服務過載,從而出現丟包。爲了實現流量控制,TCP 鏈接的每一方都要聲明本身的通告窗口(rwnd),表示本身的緩衝區最多能接收多少數據。若是其中一端跟不上對方的發送速度,就通知對方一個較小的窗口。若是窗口大小爲 0,應用層必須先清空緩衝區,才能繼續接收數據。這就是所謂的滑動窗口協議。tcp
你們可能常常遇到這種狀況,本身明明是百兆寬帶,實際下載速度每秒卻只有幾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 的大小是呈指數級在遞增。
隨着 cwnd 的增長,會發送網絡過載,此時會出現丟包。一旦發現有這種問題,cwnd 會成倍減小。
爲了減小往返次數,初始擁塞窗口的大小設定就尤其重要。默認狀況下(RFC 2581),初始 cwnd 爲 4 個 MSS。Google 建議將初始窗口改成 10 個 MSS。根據 Google 的研究,90% 的 HTTP 請求數據都在 16KB 之內,約爲 10 個 MSS。
本文介紹了 TCP 的部分工做原理,包括三次握手、流量控制、慢啓動,並闡述了 TCP 快速打開、窗口縮放、增長初始擁塞窗口大小等優化手段。內容有點偏理論,仍是須要多多實踐,才能合理掌握各類優化手段。
參考文獻: