聊聊HTTP 管線化

2023.03.27



HTTP 管線化同時依賴於客戶端和服務器的支持。遵守HTTP/1.1 的服務器支持管線化。這並不是意味著服務器需要提供管線化的回复,而只是要求在收到管線化的請求時候不會失敗。

​HTTP管線化(HTTP pipelining )是將多個HTTP請求(request)整批送出的技術,而在傳送過程中不需先等待服務器的回應。

請求結果管線化使得HTML 網頁載入時間動態提升,特別是在具體有高延遲的連接環境下,如衛星上網。在寬帶連接中,加速不是那麼顯著的,因為需要伺服器端應用HTTP/1.1 協議,同時伺服器端必須按照客戶端的請求順序回復請求,這樣整個連接還是先進先出的, 隊頭阻塞(HOL blocking)可能會發生,造成延遲。未來的HTTP/2.0 或者SPDY中的異步操作將會解決這個問題。因為它可能將多個HTTP 請求填充在一個TCP數據包內,HTTP 管線化需要在網絡上傳輸較少的TCP 數據包,減少了網絡負載。

管線化機制須透過永久連線(persistent connection)完成,並且只有GET 和HEAD 等要求可以進行管線化,非冪等的方法,例如POST將不會被管線化。連續的GET 和HEAD 請求總可以管線化的。一個連續的冪等請求,如GET,HEAD,PUT,DELETE,是否可以被管線化取決於一連串請求是否依賴於其他的。此外,初次建立連線時也不應啟動管線機制,因為對方(伺服器)不一定支援HTTP/1.1 版本的協定。

HTTP 管線化同時依賴於客戶端和服務器的支持。遵守HTTP/1.1 的服務器支持管線化。這並不是意味著服務器需要提供管線化的回复,而只是要求在收到管線化的請求時候不會失敗。

什麼是http管道化

通常,http請求總是順序發送的,下一個請求只有在當前請求的響應被完全接受的時候才會被發送。由於網絡延遲和帶寬的限制,這樣會導致在服務器發送下一個響應的時候中間有很大的延遲。

HTTP/1.1允許多個http請求通過一個套接字同時被輸出,而不用等待相應的響應。然後請求者就會等待各自的響應,這些響應是按照之前請求的順序依次到達。(me:所有請求保持一個FIFO的隊列,一個請求發送完之後,不必等待這個請求的響應被接受到,下一個請求就可以被再次發出;同時,服務器端返回這些請求的響應時也是按照FIFO的順序)。管道化的表現可以大大提高頁面加載的速度,尤其是在高延遲連接中。

管道化同樣也可以減少tcp/ip的數據包。通常MSS的大小是在536-1460字節,所以將許多個http請求放在一個tcp/ip包裡也是有可能的。減少加載一個網頁所需數據包的數量可以在整體上對網絡有益處,因為數據包越少,路由器和網絡帶來的負擔就越少。

HTTP/1.1需要服務器也支持管道化。但這並不意味著服務器需要管道化響應,而是當客戶端發出管道化請求時,服務器不會響應失敗。This obviously has the potential to introduce a new category of evangelism bugs(不會翻。。),因為僅有現代瀏覽器支持管道化。

什麼時候我們應該管道化請求

只有冪等的請求(見註1)才可以被管道化,比如GET和HEAD。POST和PUT不應該被管道化。我們同樣也不應該在建立新連接的時候發出管道化的請求,因為不能確源服務或代理是否支持HTTP/1.1。因此,管道化只能利用已存在的keep-alive連接。

多少個請求應該被管道化

如果連接過早的關閉,管道化許多請求是劃不來的,因為我們會花費很多時間用來向網絡裡寫請求,然後還不得不在新連接中重寫一遍。而且,如果較早到達的請求需要花費很長的時間完成,一個過長的管道實際上會讓用戶感知到更長的延遲。HTTP/1.1標準也沒有提供關於管道化請求理想數目的任何指導。實際上,我們建議每個服務器不超過2個keep-alive連接。顯然,這個還得依賴於應用本身。鑑於上述的原因,瀏覽器可能不需要一個持續時間特別長的管道。2個可能是比較合適的值,但是還有待測試。

如果一個請求被取消了,會發生什麼?

如果一請求被取消了,是不是意味著整個管道都被取消了呢?或者,是不是意味著這個被取消請求的響應應該被簡單的丟棄,以便這個管道中的其他請求不會被強制重發?這個答案依賴於很多因素,包括,這個被取消請求的響應還有多少沒有被收到。最原始的辦法可能是簡單的取消管道,然後重發所有的請求。僅僅當請求是冪等的時候才可以。這樣原始的方法也可以產生好的影響,因為正在管道中被發送的請求可能屬於同一個正在被取消的頁面載入組。

如果連接失敗會發生什麼?

如果連接失敗了或服務器在下載一個管道中的響應時中斷了,瀏覽器必須有能力重新開始發送被丟失的請求。這種情況可以等同於上面討論的被取消的例子。

  1. HTTP/方法的冪等性:是指一次和多次請求某一個資源應該具有同樣的副作用。
    冪等性的請求,實際上就是多次操作都不會改變結果的請求,比如GET,我可以多次從同一個地方獲取資源,但是對於資源本身來說並不會發生什麼變化,我GET10次和GET100次,資源都沒有發生任何變化。而post則不同了,我提交表單10次,和100次,造成的結果是不同的,至少數據庫里新增的數據有不同。

解釋

  1. 其實HTTP管道化就是將客戶端的FIFO隊列移到了服務端。在客戶端可以依次發送所有要發送的請求(當然這些請求是在同一個域下的),一個請求發送完之後,不必等待這個請求的響應被接受到,下一個請求就可以被再次發出。在服務器端維持的FIFO隊列,這個隊列是按照資源的重要程度排列的。比如HTML比CSS要先返回,JS,CSS比圖片先返回。
  2. 在服務器端會有一個緩衝區,來存放那些已經被處理好了但是還沒輪到被發送的響應。比如服務器先後收到了A,B兩個請求,A資源比B資源優先級要高,處理A需要10ms,處理B需要1ms,假設服務器可以並行處理請求,那麼B的響應肯定是最先處理好了的,但是B響應不能先發出去,必須待在緩衝區裡,等待A響應處理好了之後,先把A的響應發出去,B的響應才能夠被發出去。因為服務端必須要遵循FIFO這個原則。
  3. HTTP管道化不是HTTP2的內容,是對HTTP1.1協議下,服務器不能很好處理並行請求的一個改進。
  4. 管道化的有序和TCP的有序是本質上的不同,管道化的有序,是消息與消息之間的有序。TCP中的有序,組成一個消息的多個報文段之間的有序。打個不太恰當的比方,就好比是A同學吃午餐和B同學吃午餐哪個先吃完飯可以去玩電腦一樣,假設是A同學先進食堂,B同學再進食堂,他倆的吃飯速度相同,那麼按照FIFO原則,不論是A同學是吃了蘋果,梨,米飯,菜,還是B同學只吃了蘋果和米飯。雖然B同學是先吃完,他吃的少,但是在管道化中,也還一定是A同學先去玩電腦,B同學跟著。而在TCP中,就好像是在形容,這頓飯,A同學是先吃了蘋果,梨,米飯,菜還是先吃了菜,米飯,梨,這樣的內部順序。
  5. 管道做了哪些事,我的理解是創造了一個可以不用等待前一個請求的響應即可發送下一個請求的場所。至於注意些什麼,除了知道有些設備不支持,其他的我也沒實際經驗