HTTP/2 常見問題回答

oschina發表於2014-11-30

常見問題

為什麼修訂HTTP?

HTTP/1.1已經很好的服務Web超過15個年頭,但它的劣勢開始顯現。

載入一個Web頁面比之前佔用更多的資源(詳情可見HTTP壓縮頁大小統計),有效的載入這些資源很難,因為HTTP實際上對每個TCP連線,只允許一個優先的請求。

在過去,對於併發請求,瀏覽器使用多個TCP連線。然而,這也是有侷限的;如果使用了過多的連線,這既是一種計數上的高產(TCP阻塞控制是被有效否定的,導致阻塞事件影響效能和網路),也基本上是不公平的(因為瀏覽器承受的資源大於它們享有的網路資源)。

同時,大量的請求意味著“線上”有很多重複的資料。

HTTP/1.1耗費大量的開銷是與這兩個因素有關。如果發生過多的請求,會影響效能。

這些導致了相關行業成為了像雪碧、資料內聯、域共享和級聯的最佳練習場地。這些問題被認為是底層協議自身的問題,並導致在使用它們時產生了一系列的問題。

誰正在做這件事?

IETFHTTPbis工作組正在開發HTTP/2,他們負責維護HTTP協議。是由若干HTTP實現者、使用者、網路運營商和HTTP專家組成。

注意雖然工作組的郵件列表是託管在W3C網站上,不過卻不是W3C的功勞。但是, Tim Berners-Lee 和 W3C TAG與WG的程式保持了一致。

大量的人對相關工作作出了共享,不過大部分活躍參與者是來自像Firefox、Chrome、Twitter、Microsoft的HTTP棧、Curl和Akamai這樣大專案的工程師,以及若干Python、Ruby和NodeJS的HTTP實現者。

要了解更多IETF參與者,請看IETF之道。你也可以在Github的貢獻者圖表中瞭解到哪些人正在對規範做貢獻,在我們的實現者列表瞭解哪些人正在參與實施。

和SPDY是怎樣的關係?

HTTP/2 第一次出現並被討論的時候, SPDY 正得到廠商 (像 Mozilla 和 nginx)的青睞和支援, 並被看成是HTTP/1.x 基礎上的重大改善.

經過建議和投票之後, SPDY/2 被列為HTTP/2 的基礎.從那時起, 根據工作組的討論和廠商的反饋,它已經有了很多變化。

在整個過程中,SPDY 的核心開發成員都參與了HTTP/2 的發展, 其中也包括 Mike Belshe 和 Roberto Peon. 事實上,已經發布的 SPDY/4 revision 正是基於 HTTP/2的 ,因為SPDY社群現在發現它是作為一種進一步實驗反饋到 HTTP/x的工具, 而不是競爭對手.

是 HTTP/2.0 還是 HTTP/2?

工作組決定去掉小版本 (“.0”) 因為這在HTTP/1.x中導致了很多困惑.

也就是說, HTTP 的版本僅代表它的相容性,不表示它的特性和 “亮點”

和HTTP/1.x的關鍵區別是什麼?

在高版本 HTTP/2中:

  • 是二進位制的,代替原有的文字
  • 是多路複用的, 代替原來的序列和阻塞機制
  • 所以可以在一個連線中並行處理
  • 壓縮頭部資訊減小開銷
  • 允許伺服器主動推送應答到客戶端的快取中

HTTP/2為什麼是二進位制的?

比起像HTTP/1.x這樣的文字協議,二進位制協議解析起來更高效、“線上”更緊湊,更重要的是錯誤更少。因為它們對如空白字元的處理、大小寫、行尾、空連結等的處理很有幫助。

例如,HTTP/1.1定義了四個不同的方法來解析一條訊息;在HTTP/2中,僅需一個程式碼路徑即可。

HTTP/2在telnet中將不可用,但是我們有一些工作提供支援,比如Wireshark plugin

為什麼 HTTP/2 需要多路傳輸?

HTTP/1.x 有個問題叫線端阻塞(head-of-line blocking),  它是指一個連線(connection)一次只提交一個請求的效率比較高, 多了就會變慢.

HTTP/1.1 試過用流水線(pipelining)來解決這個問題, 但是效果並不理想(資料量較大或者速度較慢的響應, 會阻礙排在他後面的請求). 此外, 由於網路媒介(intermediary )和伺服器不能很好的支援流水線, 導致部署起來困難重重.

客戶端使用一些啟發式的方法(基本靠猜) 來決定通過哪些連線提交哪些請求; 由於一個頁面載入的資料量, 往往比可用連線能處理的資料量的10倍還多, 對效能產生極大的負面影響, 結果經常引起瀑布式阻塞(waterfall of blocked requests).

而多路傳輸(Multiplexing)能很好的解決這些問題, 因為它能同時處理多個訊息的請求和響應; 甚至可以在傳輸過程中將一個訊息跟另外一個摻雜在一起.

所以客戶端只需要一個連線就能載入一個頁面

為什麼只要一個 TCP 連線?

目前的瀏覽器, 每個點 (origin) 開啟 4 到 8 個連線(Connection). 而很多網站都支援多點傳輸(multiple origins), 也就是說, 光載入一個網頁, 開啟的連線數量就超過 30 個.

一個應用同時開啟這麼多連線, 已經遠遠超出了當初設計 TCP 時的預期; 每一個連線接收過多的資料, 又存在網路快取溢位的風險, 結果導致網路堵塞和資料重傳.

此外, 使用這麼多連線還會強佔許多網路資源. 這些資源都是從別人那 “偷” 來的. 你說這些應用夠遵紀守法吧? ( VoIP 就是個很好的例子).

伺服器推送的好處是什麼?

當瀏覽器請求一個網頁時,伺服器將會發回HTML,在伺服器開始傳送JavaScript、圖片和CSS前,伺服器需要等待瀏覽器解析HTML和傳送所有內嵌資源的請求。

伺服器推送服務通過“推送”那些它認為客戶端將會需要的內容到客戶端的快取中,以此來避免往返的延遲。

訊息頭為什麼需要壓縮?

來自Mozilla的Patrick McManus通過計算訊息頭對平均頁面負載的印象,對此進行了形象且充分的說明.

假定一個頁面有80個資源需要載入(這個數量對於今天的Web而言還是挺保守的), 而每一次請求都有1400位元組的訊息頭(著同樣也並不少見,因為Cookie和引用等東西的存在), 至少要7到8個來回去“線上”獲得這些訊息頭。這還不包括響應時間——那只是從客戶端那裡獲取到它們所花的時間而已.

這全都由於TCP的慢啟動機制,它會基於對已知有多少個包,來確定還要來回去獲取哪些包 – 這很明顯的限制了最初的幾個來回可以傳送的資料包的數量.

相比之下,即使是頭部輕微的壓縮也可以是讓那些請求只需一個來回就能搞定——有時候甚至一個包就可以了。

這種開銷是可以被節省下來的,特別是當你考慮移動客戶端應用的時候,即使是良好條件下,一般也會看到幾百毫秒的來回延遲。

為什麼是 HPACK?

SPDY/2 提出在每一方都使用一個單獨的GZIP上下文用於訊息頭壓縮,者實現起來很容易,也很高效、.

從那時候開始,就有了一個被證明能針對演算法中使用流壓縮(如GZIP)的重要攻擊方式 CRIME.

CRIME 讓那些能向加密流中諸如資料的攻擊者獲得了“探測”原文並進行還原的可能性。因為是Web,JavaScript使其成為了可能,而且已經有了使用針對受到TLS保護的HTTP資源的CRIME恢復cookie和認證令牌資訊的證明.

因此,我們不應該使用GZIP。由於找不到其它適合使用在這種用例下的安全有效的演算法,我們創造了一種新的,特別針對訊息頭的壓縮方案,它能進行粗粒度的操作;因為HTTP訊息頭並不常常需要改變,我們仍然可以得到很好的壓縮效率,而且更加的安全.

HTTP/2 能讓cookie(以及其他的訊息頭)更好麼?

這一嘗試被許可在網路協議的一個修訂版本上執行 – 例如,HTTP訊息頭、方法等等如何才能在不改變HTTP語義的前提下放到”網路上“.

這事因為HTTP的使用是如此廣泛。如果我們使用了這個版本的HTTP,引入了一種新的狀態機制(例如之前討論過的例子)或者改變的核心方法(幸好,這還沒有發生過), 這可能就意味著新的協議將不會同現有的Web相容.

具體地,我們是想要能夠從HTTP/1轉移到HTTP/2,並且不會有資訊的丟失. 如果我們開始”清理”訊息頭(大多數人會認同,HTTP訊息頭現在簡直是一團糟), 我們就不得不要去面對現有Web的諸多問題.

那樣做只會為採用新協議的過程中製造麻煩.

總而言之,工作組會對所有的HTTP負責,而不僅僅只是HTTP/2. 因此,我們才可以在版本獨立的新機制下運作,同時它們也能向後同現有的網路相容.

非瀏覽器使用者的HTTP會是什麼情況呢?

人們期望非瀏覽器應用程式也能夠用上HTTP/2,如果它們曾今使用過HTTP的話。

早起收到針對HTTP的“API”,HTTP/2具有效能好等特點這樣的反饋,是因為API的設計中不需要考慮像請求開銷這樣一些事情。

之前說過,我們所要考慮的主要的提升重點是在典型的瀏覽器用例下, 因為這是協議主要的使用場景。

我們的章程裡面是這樣說的:

正在組織的規範能滿足現在已經普遍部署了的HTTP的功能要求; 
具體的,(桌面端和移動端的)Web瀏覽,(“HTTP API”形式的)非瀏覽器, (大範圍的)Web服務,
還有各種(藉助代理,企業防火牆,反向代理以及內容分發網路實現的)中介。
同樣的,對HTTP/1.x當前和未來的語義擴充套件 (例如,訊息頭,方法,狀態碼,快取指令) 都應該在新的協議中支援。

注意,這裡沒有涵蓋將HTTP用於非特定行為所依賴的(例如超時,連線狀態以及攔截代理)場景中;
這些使用可能不會被最終的產品啟用。

HTTP/2 需要加密嗎?

不需要。在廣泛的討論後,工作組沒有就新協議是否使用加密(如TLS)而達成共識。

不過,有些實現者說,只有HTTP/2使用加密連結他們才提供支援。

HTTP/2為提高安全性做了什麼?

目前,HTTP/2定義了TLS的輪廓,包括版本、密碼套件和用到的擴充套件。

細節參見相關規範

也討論了額外的機制,如對HTTP://URLs(所謂的“機會主義加密”)使用TLS;參見 issue #315

現在可以用HTTP/2嗎?

HTTP/2暫時在主流瀏覽器中還不可用,不過還是有一些體驗版的可以用,或許在“每夜(nightly)”頻道可以找到。

還是有幾個伺服器可用的(包括 Akamai 和 Twitter主流網站提供了測試伺服器),以及幾個開源版的,你可以用來部署和測試。

HTTP/2會代替HTTP/1.x

工作組的目的是讓那些使用HTTP/1.x也可以使用HTTP/2,並能感受到HTTP/2所帶來的好處。工作組說過,由於人們部署代理和伺服器的方式的原因,我們不能強迫整個世界進行遷移,所以HTTP/1.x很可能仍要使用了一段時間。

HTTP/3 會出現麼?

如果通過HTTP/2引入的溝通協作機制執行良好, 那就有可能比過去更加容易的支援新版本的HTTP.

實現中的問題

為什麼規則會圍繞訊息頭幀的資料接續?

資料接續的存在是由於一個值(例如cookie)可以超過 16kb, 這意味著它不可能全部裝進一個幀裡面. 所以就決定以最不容易出錯的方式讓所有的訊息頭資料以一個接一個幀的方式傳遞, 這樣就使得對訊息頭的解碼和緩衝區的管理更加的容易.

HPACK狀態的最小和最大尺寸是多少 ?

接收一方總是會控制HPACK中記憶體的使用量, 並且最小能設定到0,最大則要看SETTING幀中能表示的最大整型數是多少,目前是 2^32 – 1.

我怎樣才能避免保持 HPACK 狀態?

傳送一個 SETTINGS 幀將狀態尺寸 (SETTINGS_HEADER_TABLE_SIZE) 設定到0, 然後 RST 所有的流,知道一個帶有ACT設定位的 SETTINGS 幀傳送了過來.

為什麼會有一個單獨的壓縮/流控制上下文?

簡潔.

原來的提案裡面流分組這個概念,它可以共享上下文,流控制等等. 那樣有利於代理 (也有利於經過它們的使用者的體驗), 而這樣做相應也會增加一點複雜度. 所以我們就決定先以一個簡單的東西開頭,看看它會有多糟糕的問題,並且在未來的協議版本中解決這些問題(如果有的話).

在HPACK中為什麼會有EOS符號?

由於CPU效率和安全的原因,HPACK的霍夫曼編碼填充了霍夫曼編碼字串的下一個位元組邊界。因此對於任何特定的字串可能需要0-7個位元的填充。

如果單獨考慮霍夫曼解碼,任何比所需要的填充長的符號都可以正常工作。但是,HPACK的設計允許按位元組對比霍夫曼編碼的字串。通過填充EOS符號需要的位元,我們確保使用者在做霍夫曼編碼字串位元組級比較時是相等的。反之,許多 headers 可以在不需要霍夫曼解碼的情況下被解析。

實現 HTTP/2 的時候我可以不用去實現 HTTP/1.1 麼?

可以,完全可以.

對於執行在 TLS (h2) 之上的 HTTP/2 而言, 如果你沒有實現 http1.1 的 ALPN 標識, 那你就就準備不需要支援任何 HTTP/1.1 特性的.

對於執行在 TCP (h2c) 之上的HTTP/2 而言, 你需要實現最原始的升級(Upgrade)請求.

只支援h2c的客戶將需要生成一個請求 OPTIONS 的請求,因為 “*” 或者一個針對“/”的 HEAD 請求已經相當安全,並且也很容易構建.  尋求實現 HTTP/2 的客戶將只需要把沒有帶上101狀態碼的HTTP/1.1響應看做一個錯誤就行了.

只支援h2c的伺服器可以使用一個固定的101響應來接收一個包含升級(Upgrade)訊息頭欄位的請求 . 沒有h2c的Upgrade令牌的請求可以使用一個包含了Upgrade訊息頭欄位的505(HTTP版本不支援)狀態碼來拒絕.  那些不希望處理 HTTP/1.1 響應的伺服器應該在傳送了帶有鼓勵使用者在升級了的HTTP/2連線上重試的連線序言之後立即用帶有 REFUSED_STREAM 錯誤碼拒絕該請求的第一份資料流.

部署的問題

怎麼除錯加密過的 HTTP/2 ?

存取應用程式資料的方法很多, 最簡單的方法是使用 NSS keylogging 加 Wireshark 外掛 (包含在最新開發版中). 這種方式對 Firefox 和 Chrome 都適用.