Web 性能優化 - TCP

原文: https://jkchao.cn/article/5a2...

TCP 負責在不可靠的傳輸信道之上提供可靠的抽象層,嚮應用層隱藏了大多數網絡通訊的複雜性能,好比丟包重發、按需發送、擁塞控制及避免、數據完整,等等。採用 TCP 數據流能夠確保發送的全部字節可以完整地被接收到,並且客戶端的順序也同樣。算法

可是 TCP 設計並未過多顧及時間,由此給瀏覽器 Web 性能帶來了挑戰。瀏覽器

三次握手

全部 TCP 鏈接一開始都必須通過三次握手。客戶端與服務器在交換應用數據以前,必須就起始分組序列號,以及其餘一些鏈接相關的細節達成一致。處於安全考慮,序列號由兩端隨機生成。緩存

  • SYN

    客戶端選擇一個隨機序列號 x,併發送一個 SYN 分組,其中可能還包含 TCP 標誌和選項。安全

  • SYN ACK

    服務器給 x 加 1,並選擇本身的一個隨機序列號 y,追加本身的標誌和選項,而後返回響應。服務器

  • ACK

    客戶端給 x 和 y 加 1,併發送握手期間的最後一個 ACK 分組。cookie

客戶端能夠在發送 ACK 分組以後當即發送數據,而服務器必須等接收到 ACK 分組以後發送數據。網絡

每一個 TCP 鏈接都要通過三次握手,假若客戶端與服務器距離過長,會形成很是大的性能影響。於是,提高 TCP 性能關鍵在於想辦法重用鏈接。併發

爲解決這個問題,人們在積極尋找各類方案,其中長連接(Keep-Alive)、負載均衡、TFO(tcp fast open)即是其中的一些解決辦法。負載均衡

長連接

Keep-Alive,HTTP 1.1 以後默認開啓,指在一個 TCP 鏈接中能夠持續發送多份數據而不會斷開鏈接。tcp

負載均衡

基本原理:客戶端(如:ClientA)與負載均衡設備之間進行三次握手併發送 HTTP 請求。負載均衡設備收到請求後,會檢測服務器是否存在空閒的長連接,若是不存在,服務器將創建一個新鏈接。當 HTTP 請求響應完成後,客戶端與負載均衡設備協商關閉鏈接,而負載均衡則保持與服務器之間的這個鏈接。當有其餘客戶端(如:ClientB)須要發送 HTTP 請求時,負載均衡設備會直接向服務器之間保持的這個空閒鏈接發送 HTTP 請求,避免來因爲新建 TCP 鏈接形成的延時和服務器資源耗費。

TCP 鏈接複用

TFO(tcp fast open)

儘管開啓了長連接,但是依然有35%的請求是從新發起一條鏈接,而握手會形成必定的延遲,TFO 的目標就是爲了去除這個延遲,在三次握手期間也能交換數據。

基本原理:

  • 客戶端發送 SYN 包,包尾加一個 FOC 請求,只有4個字節。
  • 服務端收到 FOC 請求,驗證後根據來源 ip 地址生成 Cookie(8個字節),將這個 cookie 加載到 SYN + ACK 包的末尾,發送至客戶端。
  • 客戶端緩存獲取到的 Cookie 能夠給下一次使用。
  • 下一次請求開始,客戶端發送 SYN 包,這時候後面帶上緩存的 Cookie,而後就開始正式發送數據。
  • 服務器驗證 Cookie 正確,將數據交給上層應用處理獲得相應結果,而後在發送 SYN + ACK,再也不等待客戶端的 ACK 確認,即開始發送相應數據。

TFO

網絡擁塞

擁塞:即對供不該求,對資源的需求超過了可用的資源,網絡性能降低,整個網絡的吞吐量隨之負荷的增大而減少,甚至會發生擁塞崩潰的現象。

爲了減緩網絡擁塞現象,TCP 加入許多機制用來控制雙向發送數據的速度。如流量監控、擁塞控制、擁塞預防機制等。

流量控制

流量控制是一種預防發送端過多向接收端發送數據的機制。

滑動窗口是實現流量控制的一種方法,一個簡單例子:

設 A 向 B 發送數據。在創建鏈接時,B 告訴了 A:「個人接收窗口值 rwnd = 400「 (rwnd: receiver window),所以,發送方的發送窗口不能超過接收方給出的接收窗口的數值。TCP 窗口的單位時字節,並非報文段。設每一個報文段的字節長 100,而數據報文段序號的初始值爲 1,大寫 ACK 表示首部中的確認位 ACK,小寫 ack 表示確認字段的值 ack。

從圖中能夠看出,B 進行了三次流量控制。第一次把窗口減小到 rwnd = 300,第二次又減小到了 rwnd = 100,最後減到 rwnd = 0,即不容許發送數據了。

當 rwnd = 0 時,則意味着必須由應用層先清空緩存區,才能接收剩餘數據。這個過程貫穿於每一個 TCP 鏈接的整個生命週期:每一個 ACK 分組都會攜帶相應的最新的 rwnd 值,以便兩端動態調整數據流,使之適應發送端和接收段的容量及處理能力。

慢啓動

儘管流量監控能夠防止發送端向接收端過多發送數據,可是發送端和接收端在鏈接創建之初,並不知道可用帶寬是多少,所以須要一個估算機制,而後還能夠根據網絡中不斷變化的條件而動態改變速度。

擁塞控制:防止過多的數據注入到網絡中,這樣可使網絡中的路由器或鏈路不致於過載。

慢啓動是實現擁塞控制的一種方法,此外還有擁塞預防、快速重發和快速恢復。

慢啓動,便是在分組被肯定之後,增大窗口大小,慢慢啓動。

具體實現以下:

  • 發送方經過 TCP 鏈接初始化並維護一個擁塞窗口變量(cwnd)。並規定發送端與接收端之間最大能夠傳輸的數據量爲接收窗口(rwnd)與擁塞窗口(rwnd)的最小值。

    cwnd 最初的值只有一個 TCP 段,1999年提高至 4 個 TCP 段,2013年,提高至 10 個 TCP 段。
  • 發送端向接受端發送 TCP 段後,停下來,等待確認。
  • 此後,每收到一個 ACK,慢啓動算法都會告訴發送端,cwnd 窗口增長一個 TCP 段,並能夠多發送兩個新的分組。這個階段稱爲指數增加階段。

因爲慢啓動的設計,限制了可用的吞吐量。對於大型流式下載服務的影響倒不顯著,可是對於小文件的傳輸卻很是不利,經常會出現尚未達到最大窗口請求就被終止的狀況。

簡單演示三次握手與慢啓動對簡單 HTTP 傳輸的影響。

鏈接參數:

  • 往返事件:56ms。
  • 客戶端到服務端帶寬:5 Mbit/s。
  • 客戶端和服務端接收窗口:65 535字節。
  • 初始的擁塞窗口:4 段(4 x 1460 字節 = 5.7 KB)。
  • 服務器生成響應的處理時間:40 ms。
  • 沒有分組丟失,每一個分組都要確認,GET 請求只佔 1 段。

tcp 鏈接取得文件

  • 0 ms:客戶端發送 SYN 分組開始 TCP 握手。
  • 28 ms:服務端響應 SYN - ACK 並指定其 rwnd 大小。
  • 56 ms:客戶端確認 SYN - ACK,並指定其 rwnd 大小。並當即發送 HTTP GET 請求。
  • 84 ms:服務端接收到 HTTP 請求。
  • 124 ms:服務器生成 20 KB 的響應,併發送 4 個 TCP 段(假設初始 cwnd 爲 4),而後等待 ACK。
  • 152 ms:客戶端收到 4 個段,並分別發送 ACK 確認。
  • 180 ms:服務器針對每一個 ACK 遞增 cwnd,而後發送 8 個 TCP 段。
  • 208 ms:客戶端接收到 8 個段,並分別發送 ACK 確認。
  • 236 ms:服務器針對每一個 ACK 遞增 cwnd,而後發送剩餘 TCP 段。
  • 264 ms:客戶端收到剩餘的 TCP 段,併發送 ACK 確認。

當再次發送相同請求時:

再一次發送

  • 0 ms:客戶端發送 HTTP 請求。
  • 28 ms:服務器收到 HTTP 請求。
  • 68 ms:服務器生成 20 KB 響應,此時 cwnd 已經大於發送文件所需的 15 段,所以能夠一次性發送全部數據段。
  • 96 ms:客戶端收到全部 15 個段,分別發送 ACK 確認。

擁塞預防

慢啓用使用 cwnd 做爲起始值發送數據量,隨後成倍增加。直到超過接收系統配置的擁塞閾值(ssthresh)窗口,或者發生分組丟失現象,此時擁塞預防算法介入。

因爲已經發生擁堵,必須採起刪包措施。須要從新調整 cwnd 大小,此後擁塞預防按照本身的算法來增大 cwnd 以免丟包。若再次丟包,則從頭開始。

參考

相關文章
相關標籤/搜索