天天看點

HTTP的短連接配接、長連接配接管理短連接配接模型長連接配接模型HTTP 流水線模型短連接配接長連接配接HTTP 流水線域名分片結論

打開和保持連接配接影響網站和 Web 應用程式性能。在 HTTP/1.x 裡有多種模型:短連接配接, 長連接配接, 和 HTTP 流水線。

短連接配接模型

HTTP 的傳輸協定主要依賴 TCP 提供從用戶端到伺服器端之間的連接配接。早期 HTTP 使用一個簡單模型來處理這樣的連接配接。這些連接配接的生命周期是短暫的:每發起一個請求時都會建立一個新的連接配接,并在收到應答時立即關閉。

這個簡單的模型對性能有先天限制:打開每個 TCP 連接配接都相當耗費資源。用戶端和伺服器端之間需要交換好多消息。當請求發起時,網絡延遲和帶寬都會對性能造成影響。現代浏覽器往往要發起很多次請求(十幾個或更多)才能拿到所需的完整資訊,證明了這個早期模型的效率低下。

于是 HTTP/1.1 誕生倆新模型。首先是

長連接配接模型

它會保持連接配接去完成多次連續的請求,減少不斷重新打開連接配接的時間。然後是

HTTP 流水線模型

它還要更先進一些,多個連續的請求甚至都不用等待立即傳回就可以被發送,這樣就減少了耗費在網絡延遲上的時間。

HTTP的短連接配接、長連接配接管理短連接配接模型長連接配接模型HTTP 流水線模型短連接配接長連接配接HTTP 流水線域名分片結論

HTTP/2 新增了其它連接配接管理模型。

HTTP 的連接配接管理适用于兩個連續節點之間的連接配接,如 hop-by-hop,而不是 end-to-end。當模型用于從用戶端到第一個代理伺服器的連接配接和從代理伺服器到目标伺服器之間的連接配接時(或者任意中間代理)效果可能是不一樣的。HTTP 協定頭受不同連接配接模型的影響,比如 Connection 和 Keep-Alive,就是 hop-by-hop 協定頭,它們的值是可以被中間節點修改的。

一個相關的話題是HTTP連接配接更新,在這裡,一個HTTP/1.1 連接配接更新為一個不同的協定,比如TLS/1.0,Websocket,甚至明文形式的HTTP/2。

短連接配接

HTTP 最早期的模型,也是 HTTP/1.0 的預設模型,是短連接配接。每一個 HTTP 請求都由它自己獨立的連接配接完成;這意味着發起每一個 HTTP 請求之前都會有一次 TCP 握手,而且連續不斷。

TCP 協定握手本身就耗費時間,是以 TCP 可以保持更多的熱連接配接來适應負載。短連接配接破壞了 TCP 具備的能力,新的冷連接配接降低了其性能。

這是 HTTP/1.0 的預設模型(如果沒有指定 Connection 協定頭,或者是值被設定為 close)。而在 HTTP/1.1 中,隻有當 Connection 被設定為 close 時才會用到這個模型。

除非是要相容一個非常古老的,不支援長連接配接的系統,沒有一個令人信服的理由繼續使用這個模型。

長連接配接

短連接配接有兩個比較大的問題:

  • 建立新連接配接耗費的時間尤為明顯
  • TCP 連接配接的性能隻有在該連接配接被使用一段時間後(熱連接配接)才能得到改善

為了緩解這些問題,長連接配接便被設計,甚至在 HTTP/1.1 之前。或者這被稱之為一個 keep-alive 連接配接。

一個長連接配接會保持一段時間,重複用于發送一系列請求,節省了建立 TCP 連接配接握手的時間,還可以利用 TCP 的性能增強能力。當然這個連接配接也不會一直保留着:連接配接在空閑一段時間後會被關閉(伺服器可以使用 Keep-Alive 協定頭來指定一個最小的連接配接保持時間)。

缺點

長連接配接也還是有缺點的:

就算是在空閑狀态,它還是會消耗伺服器資源,而且在重負載時,還有可能遭受 DoS attacks 攻擊。這種場景下,可以使用非長連接配接,即盡快關閉那些空閑的連接配接,也能對性能有所提升。

HTTP/1.0 裡預設并不使用長連接配接。把 Connection 設定成 close 以外的其它參數都可以讓其保持長連接配接,通常會設定為 retry-after。

在 HTTP/1.1 裡,預設就是長連接配接的,協定頭都不用再去聲明它(但我們還是會把它加上,萬一某個時候因為某種原因要退回到 HTTP/1.0 呢)。

HTTP 流水線

HTTP 流水線在現代浏覽器中并不是預設被啟用的:

  • Web 開發者并不能輕易的遇見和判斷那些搞怪的代理伺服器的各種莫名其妙的行為。
  • 正确的實作流水線是複雜的:傳輸中的資源大小,多少有效的 RTT 會被用到,還有有效帶寬,流水線帶來的改善有多大的影響範圍。不知道這些的話,重要的消息可能被延遲到不重要的消息後面。這個重要性的概念甚至會演變為影響到頁面布局!是以 HTTP 流水線在大多數情況下帶來的改善并不明顯。
  • 流水線受制于 HOL 問題。

    由于這些原因,流水線已經被更好的算法給代替,如 multiplexing,已經用在 HTTP/2。

預設情況下,HTTP 請求是按順序發出的。下一個請求隻有在目前請求收到應答過後才會被發出。由于會受到網絡延遲和帶寬的限制,在下一個請求被發送到伺服器之前,可能需要等待很長時間。

流水線是在同一條長連接配接上發出連續的請求,而不用等待應答傳回。這樣可以避免連接配接延遲。理論上講,性能還會因為兩個 HTTP 請求有可能被打包到一個 TCP 消息包中而得到提升。就算 HTTP 請求不斷的繼續,尺寸會增加,但設定 TCP 的 MSS(Maximum Segment Size) 選項,仍然足夠包含一系列簡單的請求。

并不是所有類型的 HTTP 請求都能用到流水線:隻有 idempotent 方式,比如 GET、HEAD、PUT 和 DELETE 能夠被安全的重試:如果有故障發生時,流水線的内容要能被輕易的重試。

今天,所有遵循 HTTP/1.1 的代理和伺服器都應該支援流水線,雖然實際情況中還是有很多限制:一個很重要的原因是,目前沒有現代浏覽器預設啟用這個特性。

域名分片

除非你有緊急而迫切的需求,不要使用這一過時的技術,更新到 HTTP/2 就好了。在 HTTP/2 裡,做域名分片就沒必要了:HTTP/2 的連接配接可以很好的處理并發的無優先級的請求。域名分片甚至會影響性能。大多數 HTTP/2 的實作還會使用一種稱作連接配接凝聚的技術去嘗試合并被分片的域名。

作為 HTTP/1.x 的連接配接,請求是序列化的,哪怕本來是無序的,在沒有足夠龐大可用的帶寬時,也無從優化。一個解決方案是,浏覽器為每個域名建立多個連接配接,以實作并發請求。曾經預設的連接配接數量為 2 到 3 個,現在比較常用的并發連接配接數已經增加到 6 條。如果嘗試大于這個數字,就有觸發伺服器 DoS 保護的風險。

如果伺服器端想要更快速的響應網站或應用程式的應答,它可以迫使用戶端建立更多的連接配接。例如,不要在同一個域名下擷取所有資源,假設有個域名是 www.example.com,我們可以把它拆分成好幾個域名:www1.example.com、www2.example.com、www3.example.com。所有這些域名都指向同一台伺服器,浏覽器會同時為每個域名建立 6 條連接配接(在我們這個例子中,連接配接數會達到 18 條)。這一技術被稱作域名分片。

HTTP的短連接配接、長連接配接管理短連接配接模型長連接配接模型HTTP 流水線模型短連接配接長連接配接HTTP 流水線域名分片結論

結論

改進後的連接配接管理極大的提升了 HTTP 的性能。不管是 HTTP/1.1 還是 HTTP/1.0,使用長連接配接 – 直到進入空閑狀态 – 都能達到最佳的性能。然而,解決流水線故障需要設計更先進的連接配接管理模型,HTTP/2 已經在嘗試了。

參考

繼續閱讀