HTTP/2的優先級


前言

記得HTTP/3即將標准化了。今日早讀文章由@smallbonelu翻譯授權分享。

@smallbonelu,一枚愛好跑步的前端工程師

正文從這開始~~

以正確的順序請求頁面資源對於快速的用戶體驗至關重要。想象一下,如果一個網頁上有一堆圖片,還有一個外部樣式表,一些自定義Web字體和一些在head中的腳本。如果瀏覽器首先下載了所有圖片並且最后加載了樣式表,在所有內容都加載完畢前,頁面將完全是空白頁。如果瀏覽器首先加載了所有阻塞資源,接着是Web字體和圖片,那么它可以更早地呈現頁面,並讓用戶開始看到內容,同時加載其余的圖片。我在Chrome瀏覽器性能工作上的大部分時間都花在了嘗試優化加載資源的順序以獲得最佳用戶體驗上。

使用HTTP/1.x,瀏覽器可以完全控制資源加載順序。每個連接一次只能支持一個資源請求,服務器會盡快返回請求的內容。瀏覽器可以通過決定何時請求資源以及打開多少個並行連接來安排請求。

HTTP/2讓這些事情變得更好也更復雜了。瀏覽器可以一次請求多個資源,指定一些優先級信息來幫助確定應該如何處理這些資源,然后等待服務器發回所有數據,而不是一次請求一個。如果瀏覽器和服務器都支持優先級,則應使用瀏覽器指定的規則並使用所有可用帶寬來傳遞資源,而不會有資源之間的相互競爭。

每個資源都獲取一個stream ID來標識連接上的資源,並且有三個參數用於定義資源優先級:

1.父級數據流(Parent Stream):這個數據流是一個“依賴”資源或者應該在之后被傳遞的數據流。有一個所有數據流共享的虛擬root stream 0。
2.權重(Weight):1到256之間的數字,用於標識在多個數據流共享連接時分配給此數據流的帶寬量。帶寬是相對於所有其他活動的數據流的權重分配的,而不是絕對值。
3.獨占位(Exclusive bit):一個標志,表示應該在不與任何其他數據流共享帶寬的情況下下載。

瀏覽器不一定同時知道所有資源,因此服務器能夠在新請求到達時重新確定請求的優先級也很關鍵。

那么……我們是怎么做的呢?

瀏覽器引擎

Chrome

這包括使用Chromium的優先級邏輯和網絡堆棧的所有內容。

Chrome是唯一使用獨占位的瀏覽器,它在每個資源上使用它。它構建了一長串資源,將較低優先級的資源鏈接到仍在等待的最后一個相同或更高優先級的資源。如果沒有更高優先級的資源掛起,則啟動新鏈。權重以靜態映射的方式分配,Chrome的五個內部優先級分別對應相應的權重(即HIGHEST為256)。

 

假設給定幾個請求隊列,所有請求都設置了獨占位,服務器將選擇權重最高的一個,完成傳遞后,就將其從列表中彈出並重新選擇。

假設Chrome正確構建了排序,這可能非常有效。獨占下載資源是樣式表和腳本等阻塞資源的最佳選擇。當涉及到圖片和視頻時,你可能需要一些交錯執行的任務(特別是對於漸進式圖片)。否則,在轉到下一個請求前,你將要等待每個圖片或視頻完全下載下來。

Firefox

Firefox實現了HTTP/2的樹結構,並構建了一個虛擬的數據流樹,用來對不同請求類型進行分組。Firefox對分組進行了加權,以便為更重要的組提供更多的帶寬,並且當所有節點都已完成時,空閑周期(idle cycles)可用於響應。

在根級別中,有一個“leader”組,,它的帶寬是“Other group”的兩倍。在“leader”組中,有一個叫“follower”的子組,它只有在“leader”組的直系后代完成下載后才會開始下載。例如,在權重為200的“leader”組下面,一旦所有CSS完成下載后,圖片和字體才會開始下載。一個組內的所有子資源具有相同的權重並均勻分配帶寬(同時下載所有圖片或所有腳本)。

 

從整體結構上來看Firefox非常出色,可以為推測請求定義空閑周期,但對同時下載所有資源優先級的划分並不是很好。像樣式表和腳本等這樣的阻塞資源的優先下載要比按順序下載它們才能讓解析器處理文檔要好。

Safari

這包括iOS上的所有瀏覽器(包括Chrome)。

Safari采用了一種非常簡單的方法,看起來是SPDY優先級的遺留部分。五個內部webkit優先級靜態映射到權重,並且沒有定義依賴關系。所有請求基於每個資源的優先級來划分帶寬權重進行同時下載(例如,腳本獲得圖片帶寬的三倍)。

 

這樣導致高並發性並不是很好,而且落后於Firefox的實現,在Firefox中至少follower組的資源會等到leader組資源全部完成任務之后(盡管它可能不足以證明Firefox中樹的復雜性)。

Microsoft Edge / Internet Explorer

簡而言之,Microsoft Edge(和Internet Explorer)根本不支持優先級。所有請求均勻分配帶寬(幾乎是最糟糕的情況)。

 

Servers/Hosting/CDNs

現在大多數服務器都支持HTTP/2了,通常也”支持”優先級的。支持加了引號,是因為即使一個服務器內部支持資源優先級,實際上讓它能夠與瀏覽器工作也需要調整網絡堆棧並盡可能減少輸出緩沖而不影響吞吐量。

緩沖可能是一個問題,因為服務器可以發送一堆低優先級的響應,這些響應在高優先級響應到來之前已經在緩沖區中排隊。發送高優先級響應時,無法搶占已緩沖的低優先級響應。緩沖可以來自服務器本身,TLS層,TCP發送的緩沖,甚至來自網絡上的bufferbloat,跟蹤並消除所有多余的緩沖可能會很復雜。我在今年早些時候的一篇博文中談到了一些原因和解決方案,但這並不是一個詳盡的清單。

為了測試服務器優先級的有效性,我構建了一個測試頁面,你可以在你的服務堆棧上部署該測試頁面以查看優先級是否正常工作。它專門針對Chrome的優先級邏輯,因此最好使用慢速連接上的Chrome進行測試。它先將3MB低優先級圖片排隊,然后在下載並執行高優先級腳本后,腳本會發送4個高優先級請求(一張圖片,一個頁面背景,一個自定義的webfont和一個阻塞腳本)。當優先級正常工作時,后置的高優先級請求的資源會跳過低優先級請求並快速得到響應:

 

當優先級工作不正常時,部分或全部后置的高優先級請求的資源會被延遲,直到優先級較低的請求完成為止:

 

后置請求的阻塞腳本的延遲超出了“DOM Content Loaded”的度量值,字體和2個圖片的延遲對視覺體驗產生了相當大的影響:

 

我們從哪里開始?

為了跟蹤CDN和托管服務提供商支持HTTP/2優先級的程度,Andy Davies創建了一個GitHub倉庫,用於跟蹤當前的支持狀況,任何人都可以提交測試結果來群策群力。在撰寫本文時,情況非常糟糕,只有兩個CDN確實正確地確定了優先級,並且存在一些非常令人震驚的失敗(例如每個雲提供商甚至Google的GFE)。希望通過提高對這種情況的認知,我們將能夠為優先級提供更廣泛的支持。

對托管和服務器來說,好消息是你總是可以在它們之前配置一個支持優先級的CDN來解決問題(盡管直接支持它會很好)。

在瀏覽器方面,除了敦促瀏覽器廠商以獲得更好的支持之外,沒有太多可以做的事情。其中的一些廠商可能會遇到架構問題,如他們的瀏覽器引擎在操作系統的網絡堆棧層之上,導致無法傳遞優先級信息。可能是我的偏見,但我認為Chrome是最接近“正確”的做法,但仍有相當大的改進空間。

HTTP/3也即將到來,但目前的優先級方案不會改變。這個改變是網絡堆棧的終結。在服務器端,這意味着操作系統的緩沖和擁塞控制不再起作用,服務器軟件100%負責最小化緩沖(包括擁塞控制算法以最小化緩沖區)。
那么就說到這里,希望為了HTTP/2和一個安全,高性能的網絡,我們可以在2019年修復資源優先級。

關於本文
譯者:@smallbonelu
譯文:https://github.com/FE-star/speed/blob/master/2018.06.md
作者:@Patrick Meenan
原文:https://calendar.perfplanet.com/2018/http2-prioritization/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM