文 / Patrick Meenan
譯 / John
原文
https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/HTTP/2意味着更快的網頁加載速度,而Cloudflare在很久之前也為所有客戶提供了HTTP/2通路服務。但是其中HTTP/2的一項特性——加載優先級,并沒有達到預期的效果。事實上優先級特性本身并沒有什麼問題, 真正地問題在于浏覽器中優先級特性的實作方式。
現在,Cloudflare推出了對于HTTP/2優先級的優化更新,也就是讓我們的伺服器有能力控制優先級政策進而真正提高網頁的加載速度。在此之前,浏覽器已經能夠控制并決定加載網頁内容的方式與時長。而現在我們希望能通過對優先級模型進行更新,将網頁控制權盡可能地交給網站所有者。客戶可以在Cloudflare儀表闆的“Speed”頁籤中啟用“增強HTTP/2優先級”——将更新的排程方案覆寫至浏覽器預設設定進而顯著提升網頁通路體驗(根據多個場景下的測試,我們發現性能普遍提升達50%)。借助Cloudflare Workers,網站所有者可以根據需求進一步定制使用者的網頁浏覽體驗。
背景
Web頁面一般由數十個甚至數百個單獨的資源組成,浏覽器将這些資源加載并組裝成最終顯示的内容。這包括使用者與之互動的可見内容(HTML、CSS、圖像)以及網站本身的應用程式邏輯(JavaScript)、廣告、跟蹤網站使用情況的資料分析與營銷跟蹤信标等。根據何種優先級政策對這些資源的加載過程進行排序,直接決定使用者等待網頁加載所需要的時間以及檢視網頁内容并與其進行互動的體驗。
浏覽器本質上是一個HTML處理引擎,每當加載一個網頁時,浏覽器會周遊HTML文檔并遵循訓示,按照從HTML開始到結束的順序建構頁面;與此同時,浏覽器也會引用層疊樣式表(CSS)進而獲悉并設定頁面内容的樣式;一些情況下,為了明确設定要顯示的内容樣式,浏覽器會延遲顯示網頁内容直到層疊樣式表被加載完成。文檔中引用的腳本可能有以下幾種不同的行為:如果腳本被标記為“異步”或“延遲”,則浏覽器可以繼續處理文檔并在腳本可用時運作腳本代碼;如果腳本沒有被标記為“異步”或“延遲”,則浏覽器必須停止處理文檔,直到腳本下載下傳完成并被執行才會繼續處理文檔,這些沒有被标記的腳步被稱為“阻塞”腳本——顧名思義,“阻塞”腳本阻止浏覽器繼續處理文檔直到其被加載和執行。
HTML文檔分為兩部分:<head>文檔的開頭部分包含顯示内容所需的浏覽器樣式表、腳本和其他說明;<body>文檔位于頭部檔案之後,包含浏覽器視窗中顯示的實際頁面内容(腳本和樣式表也被包含在其中)。在浏覽器通路至文檔正文也就是<body>之前,網頁不會向使用者顯示任何内容,頁面将保持空白。是以,浏覽器需要盡可能快地加載頭部檔案。
在處理文檔的同時,通常浏覽器也負責确定以什麼樣的順序加載建構頁面所需的不同資源。在HTTP/1.x的情況下,浏覽器單次從任一伺服器端所請求的内容量被限制(通常是6個連接配接,每個連接配接一次隻能請求一個資源),是以資源的加載順序是由浏覽器通過請求的方式嚴格控制的。而對于HTTP/2,情況發生了很大的變化,浏覽器可以一次請求所有的資源(至少了解有多少資源等待被加載),進而便于其向伺服器提供有關資源傳輸的詳細說明。
最優資源排序
大多數浏覽器在加載頁面的過程中存在最佳的加載資源優先級政策,其直接促成了良好的使用者體驗;同時最佳政策與非最佳政策所造成的網頁加載耗時可能存在高達50%的差異。
如上所述,在浏覽器呈現全部網頁内容之前的頁面加載時期,會在CSS上被阻止并阻止HTML的<head>部分中的JavaScript;是以在這一期間最好使用全部連接配接帶寬以充分下載下傳被阻塞的資源,并按照HTML定義的順序一次下載下傳一個資源以便于浏覽器在下載下傳下一個阻塞資源時可同時解析并執行上一個項目,實作下載下傳和執行的流水線化操作。

傳統的并行下載下傳或依次下載下傳所需要的下載下傳時間相同,而如果按照順序下載下傳并在第二個腳本下載下傳時執行第一個腳本,那麼這會明顯縮短網頁資源的加載時間。
一旦加載渲染項阻止内容,最佳加載狀态可能取決于特定網站甚至業務優先級情況(如使用者内容與廣告分析對提供商而言的權重)。其中尤為重要的一項的是字型,浏覽器僅在将樣式表應用于即将顯示的網頁内容之後才會确認所加載字型。因而當浏覽器确認所加載字型前,現存的即将被顯示在網頁上的文本就應當被準備完畢。擷取字型過程所發生的任何延遲最終都會導緻螢幕上顯示空白文本或以錯誤字型顯示文本。
為確定網頁加載的正常,我們應當權衡以下内容:
- 應盡快加載頁面可見部分中的自定義字型與圖像——這直接關乎頁面加載時期的使用者視覺體驗。
- 非阻塞JavaScript相對于其他JavaScript資源應當以串行方式下載下傳,同時每個JavaScript都以流水線形式加載。JavaScript可能包括面向使用者的應用程式邏輯、使用者行為分析與營銷跟蹤信标,一旦出現延遲即可導緻業務跟蹤名額的下降。
- 借并行下載下傳可實作更好的圖像加載效果。圖像檔案的前幾個位元組包含浏覽器頁面布局所需要的圖像尺寸,并行的逐行圖像下載下傳允許在浏覽器僅接收原始資料的50%基礎之上優先完成視覺上的圖像加載。
權衡以上内容,我們可得出以下可達到良好運作狀态的政策:
- 按順序政策下載下傳自定義字型,并使用可見圖像分割可用帶寬。
- 按并行政策下載下傳圖像,切割“圖像”以便于按照所配置設定的帶寬逐行加載圖像。
- 當沒有更多等待被處理的字型或圖像時:
- 非阻塞腳本按順序下載下傳,并使用不可見的圖像分割可用帶寬。
- 按并行政策下載下傳不可見圖像,切割“圖像”以便于按照所配置設定的帶寬逐行加載圖像。
通過采取以上政策,我們希望浏覽器能夠盡可能快地加載使用者可見的網頁内容,盡可能減少應用程式邏輯所造成的延遲,并以盡可能短的時間完成網頁布局與不可見圖像的加載。
實際案例
為了便于說明,我們将以電子商務網站的簡化産品類别頁面作為典型案例,其中頁面具有以下附加元件:
頁面本身的HTML檔案,使用藍色框表示。
1個外部樣式表(CSS檔案),使用綠色框表示。
4個外部腳本(JavaScript),使用橙色框表示。其中2個在頁面開頭處的腳本為阻塞腳本,使用較暗的橙色陰影框表示;除此之外還有2個異步腳本。
1個自定義Web字型,使用紅色框表示。
13個圖像,使用紫色框表示。頁面徽标和4個産品圖像在視口中可見,使用較深的紫色框表示;8個産品圖像需要滾動頁面才能看到。
為簡單起見,我們假設以上所有資源的大小相同,每個資源在通路端需要1秒時間連接配接與下載下傳,加載所有資源總共需要20秒,這裡我們主要研究采用不同的加載方式會對使用者浏覽網頁的體驗帶來什麼影響。
這就是我所描述的采用“最佳加載政策”加載資源時,浏覽器所呈現出的效果:
- 啟用全部連接配接,加載HTML、CSS和阻止腳本的前4秒内,頁面為空白。
- 第4秒,頁面僅顯示了背景與結構卻未顯示文本與圖像。
- 第5秒,頁面文本被成功顯示。
- 5~10秒,圖像逐漸被加載;開始時圖像模糊,随後圖像被快速銳化;第7秒時浏覽器幾乎完成了全部圖像加載
- 第10秒,視覺視窗中的所有可視化内容都已加載完畢。
- 10~12秒,異步JavaScript被加載與執行,随後包括資料分析、營銷信标在内的其他所有非關鍵邏輯被加載與執行。
- 12~20秒,其他的産品圖像開始被加載以便為使用者接下來可能的網頁滾動行為做好準備。
常見浏覽器的優先級政策
常見的幾個浏覽器引擎都采取了不同的優先級政策,耐人尋味的是其中沒有一個符合“最佳優先級加載政策”的要求。
1)Microsoft Edge和Internet Explorer
Microsoft Edge和Internet Explorer 不支援附加元件的優先級排序,因而所有内容的加載方式都基于HTTP/2的預設設定,即并行加載所有内容并為所有内容均勻配置設定帶寬。預計在未來,采用Chromium引擎的新版Microsoft Edge會在此方面迎來極大改善。而在我們的示例頁面中,并行加載與均勻帶寬配置設定意味着浏覽器的絕大部分加載過程都停留在頭部檔案之上,而圖像等資源則會減慢阻塞腳本與樣式表的傳輸速度。
在大多數内容被成功顯示之前,使用者視覺會在長達19秒的時間内不得不停留在空白頁面,随後經曆1秒的文本顯示延遲才能看到網頁所有元素。這就意味着使用者使用IE核心的浏覽器觀看動畫時需要耐心等待頁面元素全部加載完成,這無疑是對使用者浏覽網頁體驗的巨大影響。
2)Safari
Safari 同樣采取并行政策加載所有資源,但Safari會根據不同資源的重要程度為其劃分合适且足夠的帶寬(例如:渲染腳本和樣式表等阻塞資源比渲染圖像更為重要);而圖像雖采用并行加載的政策,但其也與阻塞渲染資源同時被加載。
雖然采用了與Edge類似的并行加載政策,但Safari通過為阻塞渲染資源配置設定更多帶寬,實作更快的網頁加載過程:
- 加載開始後的約8秒,樣式表和腳本已加載完畢,因而頁面開始被顯示;由于圖像采用并行加載政策,在此期間隻有部分圖像被加載(相對于采用逐行加載政策的圖像而言更加模糊),但加載效果要遠勝于IE與Edge浏覽器。
- 約第11秒,字型已加載完畢,文本正常顯示的同時有更多帶寬被投入圖像資料的加載當中,這讓圖像的清晰程度進一步提升,這樣的水準已經接近于采用“最佳加載政策”的第7秒加載效果。
- 接下來的9秒當中,随着完成下載下傳的資料進一步增多,圖像變得愈發清晰,直到第20秒完成全部加載活動。
3)Firefox
Firefox建構一個依賴關系樹,該樹将資源分組并安排這些組采取依次加載或組之間共享帶寬的形式進行加載。在給定組内,資源在共享帶寬的同時被下載下傳;而那些圖像則被計劃在阻塞渲染資源之後,采用并行政策的方式進行加載,但阻塞渲染腳本和樣式表也會被并行加載,這樣便無法從流水化操作中獲得顯著的性能提升。
在我們的示例中,由于圖像加載過程被推遲到樣式表加載完成之後,因而最終的實際加載過程會略快于Safari。
- 第6秒,背景與産品圖像的模糊版本構成了網頁的大緻内容。其整體觀感和Safari在第8秒時的加載效果與采用“最佳加載政策”浏覽器的第4秒加載效果相似。
- 第8秒,字型已加載完畢,文本正常顯示的同時圖檔愈發清晰(其與Safari在第11秒時的加載效果與采用“最佳加載政策”浏覽器的第7秒加載效果相似)。
- 剩餘的12秒内,産品圖像逐漸變得更加清晰。
4)Chrome
Chrome以及所有基于Chromium核心的浏覽器會将資源按照一定優先級順序排序至待加載清單中,這對于阻塞渲染資源來說非常有效;按順序加載政策為這些資源的加載過程所帶來的好處不言而喻,但其頁面中的圖像在開始下一張圖像之前需要加載至100%才可成功顯示。
在實際測試中,Chrome的加載效果幾乎與采用“最佳加載政策”的浏覽器相同,唯一的差別是Chrome的圖像采用按順序加載的方式一次性加載完畢而非并行加載:
- 前5秒,Chrome體驗與采用“最佳加載政策”的浏覽器相同——前4秒背景加載完畢,第5秒文本加載完畢。
- 5~10秒,可見圖像被依次下載下傳直到第10秒時全部圖像加載完畢(與采用“最佳加載政策”的浏覽器相比,Chrome在第7秒時,其圖像稍微模糊但在随後的3秒内被快速銳化)。
- 10秒後,頁面的可視部分資源加載完畢(此成績與采用“最佳加載政策”的浏覽器相同),接下來的10秒則會被用于運作異步腳本并加載隐藏圖像(此政策與采用“最佳加載政策”的浏覽器相同)
視覺比較
上述浏覽器的不同加載政策所展現出的視覺差異可能會十分明顯,即使這些浏覽器廠商都花費了足夠多的時間與技術來優化頁面資源加載過程:
伺服器端的優先級
用戶端(浏覽器)請求HTTP/2優先級排序政策,随後由伺服器根據請求決定接下來做什麼。很多伺服器根本不支援使用優先級做任何事情,但是對于那些支援優先級的伺服器,它們都尊重用戶端的請求。我們可以通過考慮用戶端的請求來決定在伺服器端使用何種最佳優先級。
根據規範,HTTP/2優先級可以看作是一個依賴樹,此依賴樹需要完全掌握所有正在進行的請求以便能夠考慮到所有資源的加載狀況并優先決定關鍵資源的加載。由于不同的浏覽器具有不同的加載政策,而不同層級的伺服器各有差異,這種十分複雜的優先級政策很難在浏覽器端被輕易實作。為了便于優先級的管理,我們開發了一種更簡單的優先級排序方案,該方案具有優化排程所需優先級的靈活性。
Cloudflare優先級排序方案由64個優先級“級别”組成,在每個優先級内,一組資源可确定如何在不同優先級之間共享連接配接:
在進入下一個較低優先級之前,浏覽器會轉移所有較高優先級的資源。
在給定的優先級内,有3個不同的“并發”組:
- 0:并發“0”組中的所有資源按照請求的順序使用100%的帶寬依次發送。隻有所有并發“0”組的資源被下載下傳完成之後,浏覽器才會考慮同一級别的其他組。
- 1:并發“1”組中的所有資源按請求順序依次發送。可用帶寬在并發“1”組和并發“n”組之間均勻配置設定。
- n:并發“n”組中的資源是按照每個資源所配置設定的帶寬資源并行發送。
實際上,并發“0”組對于需按順序處理的關鍵内容(腳本,CSS等)而言非常有用;并發“1”組對于不太重要的内容而言非常有用,因為這些内容可以與其他資源共享帶寬,但資源本身仍可以從順序處理(異步腳本,非漸進式圖像等)中受益;并發“n”組對于依賴并行處理(漸進式圖像,視訊,音頻等)的資源而言非常有用。
Cloudflare預設優先級
啟用Cloudflare時,增強的優先級排序可實作上述資源的“最佳”排程。應用的特定優先級如下所示:
該優先化方案允許串行發送并呈現阻塞内容,随後并行發送可見圖像。接下來通過某種程度的共享,覆寫頁面内容的其餘部分以平衡應用程式和内容加載。這裡的“*If Detectable”警告是說,并非所有浏覽器都區分不同類型的樣式表和腳本,但這不影響浏覽器的加載速度。預設情況下Cloudflare會比其他浏覽器,特别是Edge和Safari快50%。
人為可控的自定義優先級
盡管在預設情況下Cloudflare可實作更快加載速度,但真正有趣的是配置優先級的能力也向Cloudflare Workers公開,這樣站點就可以覆寫資源的預設優先級,或者實作它們自己的完整優先級計劃。
如果從業人員為響應添加“cf-priority”标頭,則Cloudflare邊緣伺服器将使用指定的優先級和并發響應。标頭的格式<priority>/<concurrency>就像response.headers.set('cf-priority', “30/0”);将給定響應的并發度為0的優先級設定為30。類似地,将“30/1”并發設定為1,将“30 / n”并發設定為n。
借助上述靈活性舉措,站點可以調整資源優先級以滿足其多樣化需求。例如,當浏覽器識别出使用者正在閱讀某一網頁時,使用者的視覺重心位于目前網頁之上;而如果我們想要提升下一頁的觀感,那麼我們可以嘗試提升某些關鍵異步腳本的優先級或增加關鍵圖像加載的優先級。
為了幫助通知任何優先級決策,Workers運作時還在傳遞給Worker的fetch事件偵聽器(request.cf. requestpriority)的請求對象中公開浏覽器請求的優先級資訊。傳入的請求優先級是以分号分隔的屬性清單,其類似于:
- weight:HTTP/2優先級的浏覽器請求權重。
- exclusive:浏覽器請求的HTTP/2獨占标志(基于Chromium的浏覽器為1,其他為0)。
- group:請求組的HTTP/2流ID(Firefox僅為非零)。
- group-weight:請求組的HTTP/2權重(Firefox僅為非零)。
這僅僅是個開始
浏覽器調整和控制響應優先級的能力可以讓許多未來相關項目從中受益。而我們則是在此基礎之上加入了獨創的進階優化——也就是讓整個優先級排序過程暴露給開發者以便于開發者基于網站其他研究人員的參考資訊嘗試不同的優先級政策。通過Apps Marketplace,我們還在Workers平台之上建構新的優化服務,并使其可供其他站點使用。
————————————————
版權聲明:本文為CSDN部落客「LiveVideoStack_」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:
https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/90684091「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。