網路技術

HTTP 的理想性能

提高 Web 性能的一個簡明的目標是減少用戶的等待時間,將頁面儘可能快地呈遞到用戶面前。
對於 HTTP 來說,這就意味著一個理想的協議交互應該是這樣的:

也就是說,一個頁面的載入需要在最少的往返次數里上傳下載最小的數據量。
額外的數據傳送不僅耗費了更多的時間,還可能導致擁塞的丟包,嚴重影響性能。
以這樣的標準來看 HTTP 的話如何呢,我們又可以如何改進它?

HTTP/1.1

從許多方面來看,HTTP/1.1 都是一個優秀的協議,但是從現代 Web 的使用方式來看,HTTP/1.1的性能是明顯不夠的,一般網頁載入過程大概是這樣:

嗯…看起來並不是那麼理想。
客戶端需要請求伺服器多次來獲取 HTML 中的圖片資源,先是 HTML,接著是 CSS 和 JavaScript。這個過程中的每一次數據交換,都使頁面載入的完成多等待了一個往返的等待時間。有悖於我們理想中的 「最少的往返次數「 。
還有,只是為了獲取頁面中的其他數據而去發送請求,也與我們的 「最少數據傳送」 原則相違背。
因為冗長的請求頭例如 Referer、User-Agent 和 Cookie 在重複的在每一次請求中被傳送。
最後,因為 HTTP/1 中存在隊頭阻塞,在實際應用中常常把資源整合進 CSS spriting、使用內聯 和 串聯,這些都是非常巧妙的 HTTP/1 表現技巧,但這也是有代價的。這致使客戶端下載了更多的數據,違背了我們 "最小下載量" 的理念,也意味著我們並沒有做到絕對快地將網頁呈現在用戶面前。
總的來說,HTTP/1.1 並不是一無是處,在性能上還是有可取之處的。比如它的緩存機制,避免了客戶端下載已經下載過的數據。還有條件請求,避免了在已有先前的數據的情況下重複下載大文件。

HTTP/2

HTTP/2 試圖從這幾個方面來解決問題:

  1. 多路傳輸意味著隊頭阻塞將不再是問題,你可以在一個單一的 HTTP 連接中載入整個網頁,不需要去做多餘的請求,數據浪費優化技術也可以放在一邊了。
  2. 報頭壓縮解決了冗餘的報頭帶來的資源浪費,現在你可以接受幾十(甚至數百)個IP數據包請求,越來越接近「最小數據量」的目標了。
  3. HTTP/2 伺服器推送允許伺服器預測客戶端將會需要的資源,省去了多餘的客戶端請求。

所以,一次 HTTP/2 的交互差不多是這樣的:

你可以看到伺服器自動的把 CSS、Javascript 和 圖片資源發送給了客戶端,不需要客戶端去主動請求。它知道客戶端將要去請求這些資源,所以利用伺服器推送把資源發送給了客戶端,減少了一次網路往返。

請注意,這並不是說,這都是很容易的;還有很多關於 HTTP/2 公認的問題,特別是在推送的時機上。我接下來會單獨討論。

HTTP/2 + 緩存摘要

關於伺服器推送的一個常見問題是:「如果客戶端已經有緩存了,該怎麼辦?」 因為推送總是默認的,伺服器還是有可能發送客戶端不需要的東西。

HTTP/2 利用 RESET_STREAM 賦予了客戶端取消推送的能力來解決這個問題。儘管如此,還是有一個網路往返被浪費掉了。記住,我們的理想是只發送客戶端需要的數據。

一個解決方案是利用一個緩存摘要來讓伺服器知道客戶端已經存在的資源。

因為緩存摘要利用了 Golumb 壓縮集,所以客戶端只需要利用少於一千個位元組就能告訴伺服器自己已有的資源。

這樣,我們就避免了額外的往返、數據並聯和串聯的浪費,更貼近我們的目標了。

目前,緩存摘要只是一個提議,但在 HTTP 社區關注度非常高,希望在不遠的將來能看到它在實際中運用。

TCP

截至目前,我還沒有談到瀏覽器使用的其它協議對性能產生的影響。

然而,許多信息以上的圖表中都沒有表示出來。TCP 在新建一個連接之前需要進行三次握手。

這意味著只需要更少的網路往返就可以建立連接,但卻在每一次連接中增加了一些數據。

TCP 快速連接 允許應用程序發送 SYN 和 SYN+ACK 數據包來避免這個問題,但目前只支持 Linux 和 OS X。此外,TFO 和 HTTP 的使用也出現了一些棘手的問題,但社區已經在著手解決了。
TFO 無法保證在 SYN 上發送的數據只出現一次,很容易被複制甚至惡意攻擊。所以,HTTP POST 並不是一個很好的方式來進行第一次 TFO 請求。更讓人頭疼的是,一些 GET 也存在問題,瀏覽器不知道如何去偵測哪一個 URL 是用來發送這個的。

TLS

在 TCP 握手完成之後,TLS 又開始了另一次握手:

在 HTTP 可以進行數據傳送之前 TLS 先要進行兩次往返。如果這不是第一次訪問伺服器,session tickets 能避免其中的一次往返。

不久以後,在不是第一次訪問的情況下,TLS 1.3 將會支持 「0 次往返」。也就是說,HTTP 將能在第一次往返中就進行數據的傳送,避免了一些延遲。然而,像 TCP 快速連接那樣,你需要保證第一次往返中發送的數據不出問題。

下一代 HTTP

TCP 快速打開和 TLS 1.3 都能減少新建連接的通信量。另一個方法是儘可能的利用好已經打開了的連接。

為此,人們正積極討論如何能讓連接聚集更加的有效。這不僅能減少新建連接的開銷,更讓已經存在的連接更加的高效,使 TCP 保持持久和繁忙。

其中包含了將證書推送到客戶端,以使該連接可以被更多終端使用。

一些更激進的方案也在討論中,比如用 UDP 替換 TCP,QUIC。過度到 QUIC 還有很長的路要走。但從性能上來考慮,能不改變客戶端的操作系統的情況下在一次往返之內完成握手是非常吸引人的。此外,能在緩衝中獲取到數據意味著 TCP 中的隊頭阻塞將不再是問題。在發送少量數據之後就可以將頁面傳送到用戶面前。

距離 QUIC 的實現還遠,所以我們短時間內不會見到基於 UDP 的 HTTP 標準。但是我們可以從 QUIC 中來認識我們想要 TCP 如何更加高效,使 Web 的性能突飛猛進。錯綜複雜的互聯網將會如何發展,讓我們拭目以待。
原文鏈接:Ideal HTTP Performance

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0

You may also like

Leave a reply

您的電子郵箱地址不會被公開。 必填項已用 * 標註

此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據