當前位置:
首頁 > 科技 > 技術乾貨:HTTP/2之伺服器推送最佳實踐

技術乾貨:HTTP/2之伺服器推送最佳實踐

HTTP/1.X出色地滿足互聯網的普遍訪問需求,但隨著互聯網的不斷發展,其性能越來越成為瓶頸。IETF在2015年發布了HTTP/2標準, 著重於提高HTTP的訪問體驗, HTTP2優勢主要包括: 二進位傳輸、頭部壓縮、多路復用和伺服器推送(Server Push)。

截止目前, 大部分CDN廠商已經宣布支持HTTP/2,然而」支持」大多省略了伺服器推送(ServerPush)特性。估計這和nginx開源版本沒有支持Server Push相關。

為提供完備的HTTP2能力,騰訊CDN現已完成HTTP/2的Server Push支持,並完成了詳細的性能測試。

序言

在介紹Server Push功能之前,先來分析網站的載入過程。圖1是騰訊課堂(https://ke.qq.com/index.html)的時間瀑布圖。

a) 首先瀏覽器請求主頁面index.html,服務端響應內容;

b) 獲取到主頁應答,瀏覽器開始解析主頁的html標籤,發現構建DOM樹還需要CSS, GIF, JS等資源;

c) 發起針對CSS,GIF,JS的內容請求;

d) 獲取並解析JS和CSS等內容, 然後繼續請求依賴資源。

圖1 騰訊課堂域名的時間瀑布圖

如果服務端接收到客戶端主請求,能夠「預測」主請求的依賴資源,在響應主請求的同時,主動並發推送依賴資源至客戶端。客戶端解析主請求響應後,可以」無延時」從本地緩存獲取依賴資源, 減少訪問延時, 提高訪問體驗,也加大了鏈路的並發能力。Server Push正是基於此原理來提高網路體驗。

圖3說明了若採用服務端推送的功能,則JS/CSS資源基本可以和HTML資源同步到達,瀏覽器可以「無延時」獲取JS/CSS資源,客戶端的延時最多可以減少一個RTT。

構建一個簡單的例子來驗證我們的說法。圖4所示為simple_push.html代碼,頁面依賴資源simple_push.js和simple_nopush.js, 頁面大小均不超過1KB,主要時間消耗在傳輸延時。如圖5所示為推送simple_push.js和不推送simple_nopush.js的效果對比。

圖4 推送測試HTML代碼

圖5 不推送&推送的效果對比

我們上線了一個測試demo網站(https://http1.gtimg.cn/push/mypush.html)。網頁上展示一張世界地圖,由400個小圖片組成。對比三種訪問方式:HTTP/1.1、HTTP/2(無Server Push)和 HTTP/2(Server Push)。Server Push選擇推送第150~179個共30個小圖。訪問性能數據對比如圖6所示:可以發現預推送比無推送有一定的性能提升(受網路延時和客戶端行為影響,結果存在波動,後文有相應分析)。

圖6 demo網站測試

簡要介紹了Server Push的優化原理之後,伴隨而來的疑問,推送什麼資源,怎麼去推送,以及比其他優化技術有什麼優勢?讀完本章,這些問題將一一得到解答,文章最後用實例展示Server Push的應用場景和性能優化效果。

1

推送實現

1、標識依賴資源

W3C候選推薦標準(https://www.w3.org/TR/preload/)建議了依賴資源的兩種做法:文件內

標籤和HTTP頭部攜帶, 表示該資源後續會被使用, 可以預請求, 關鍵字preload修飾這個資源, 寫法如下:

a) 靜態Link標籤法:

b) HTTP頭表示法:

Link:

; rel=preload; as=style

其中rel表明了資源是預載入的,as表明了資源的文件類型。另外,link還可以用nopush修飾,表示瀏覽器可能已經有該資源緩存,指示有推送能力的服務端不主動推送資源,只有當瀏覽器先檢查到沒有緩存,才去指示服務端推送資源,nopush格式寫成:

Link: ; rel=preload; as=script;nopush。

2、推送資源

用戶訪問CDN,主要包括直接訪問的邊緣節點, 若干中間節點和客戶源站,路徑中的每層都可以對請求做分析,預測可能的依賴資源,通過插入靜態

標籤或者增加響應頭部返回給瀏覽器。 CDN的推送主要採用頭部攜帶推送信息。

a) 客戶端指定推送資源

客戶端通過url或者請求頭說明需要的資源url,寫法如下:

或者:

GET /simple_push.html HTTP/1.1

User-Agent: curl/7.49.1

Accept: */*

X-Push-Url: simple_push.js

b) CDN節點指定推送資源

CDN節點針對請求資源配置推送資源, 基礎配置如下:

location ~ 「/simple_push.html$」 {

http2_server_push_url /simple_push.js

}

c) 源站指定推送資源

通過增加響應頭link通知客戶端或者CDN節點,後續希望推送的依賴資源,中間具有 推送功能的節點(如CDN節點)可以基於此信息進行資源請求與推送.

3、功能實現

圖7所示為CDN的Server Push架構, 基本流程如下:

a) 用戶請求到達伺服器之後,依賴資源預測模塊根據請求頭或者配置預測瀏覽器需要的資源,該推送資源url必須是和主請求是同一host。如果不屬於同一host,伺服器拒絕推送資源。

b) 伺服器通過PUSH_PROMISE楨告訴瀏覽器準備推送的資源路徑,該信息在原主請求流上發送,必須優先主請求響應發送,否則瀏覽器可能在推送資源到達前已經發起了依賴資源請求,造成重複和浪費.

c) 依賴資源請求模塊構造和主請求一樣的請求信息,在本地或後端伺服器請求推送資源,並主動創建新的HTTP/2請求流,後續伺服器就可以發送資源響應,推送資源響應在服務端創建的流上傳輸,主頁面響應在原始流傳輸。

圖7 CDN的Server Push模塊改造示意圖

CDN節點的推送資源發送順序在主請求響應之前,如圖8所示,主要基於以下因素考量:

d) 推送資源一般是靜態的緩存命中率高的資源,如JS、CSS、字體和圖片等。這些資源可以從源站預先推送並緩存到CDN節點。相比之下, 主頁面變更較多,需要等待網路IO去源站取數據。同時,CDN邊緣節點到瀏覽器的RTT一般是比CDN節點到源站的RTT更短。所以在取到主頁面最新響應之前,有充足的時間去推送資源。

e) 資源推送可以探測提高TCP擁塞窗口,窗口逐漸增大,後續可以一次性發送完主頁面響應。TCP擁塞窗口對推送影響將在下文第三部分討論。

f) 在等待主請求響應的網路IO時間期間,推送資源可以是無優先順序關係,資源推送優先順序對推送影響也將在下文第三部分討論。

圖8 推送時間點位於主頁面響應之前

2

Server Push技術對比

1、縱向對比

Server Push相對應沒有Server Push的具體提升如下:

a) Nopush載入耗時:Tnopush = RTT+ max(RTT, size(HTML)/BandWidth)+size(JS)/BandWidth

b) push耗時:Tpush = RTT + size(HTML)/BandWidth + size(JS)/BW

c) 改善效率:diff =1 - Tpush/TnoPush

所以決定推送是否有改善性能的衡量因素是size(HTML/BandWidth)和RTT誰大。這裡引入BDP(BandWidth-Delay product, 帶寬時延乘積)概念。BDP描述了單位時間內該帶寬能傳輸的數據大小。如果size(HTML)

2、橫向對比

HTTP/1.1中有個資源內聯(Resource Inlining)技術,把資源內容拷貝到HTML標籤中。比如說

其中1.js會調用2.js文件,3.js和4.js沒有調用其他JS。

正常沒推送的例子載入時間表格會是

圖10 資源載入優先順序的nopush&push效果圖

可以看出是因為1.js的載入優先順序本應該在3.js和4.js之前,但是預先推送了3.js和4.js,然而1.js需要重新請求,並觸發2.js請求,導致等待1RTT接收2.js。所以Push比No Push的效率更差。

3、內核緩衝區

HTTP/2的請求優先順序並不能影響已經在內核發送緩衝區的數據。假設內核發送緩衝區大小比TCP擁塞串口大,導致服務端發送低優先順序的數據,存在內核緩衝區。這時,後續有高優先順序的響應必須等內核緩衝區空出才能被完成。假設我們訪問一個HTML頁面,這個HTML頁面需要回源站取數據,而HTML需要的靜態JS資源緩存在CDN邊緣節點上。在回源站的等待時間內,把靜態JS資源發送給瀏覽器。如果這時候靜態JS資源很大,塞滿了內核發送緩衝區,此時HTML響應已經到達CDN邊緣節點,卻不得不等內核緩衝區有空間才能繼續發送。等待瀏覽器解析HTML內容後續的link請求也會被推遲。

4、瀏覽器緩存

推送瀏覽器已緩存的資源有可能使的載入時間更長,並且浪費帶寬資源。重複推送已緩存的資源,如果沒有額外的空閑帶寬傳輸,網路會阻塞它之後正常的請求,導致拖累了整個網站的載入時間。

4

網站測試

我們對現網一些網頁進行Server Push性能測試,因為推送要求同一個域名下的HTTP/2請求,為了規避非HTTP/2和跨余名帶來的干擾,我們設置了代理節點,代理節點完成HTTP/2支持和域名收歸,同時配置Server Push功能,觀察網頁的載入收益。為了準確測試Push帶來網路時延變化,需要穩定的網路環境,在chrome設置網路環境mytest(RTT: 200ms, Download: 29Mb/s, Upload: 14Mb/s),以下的例子都在該網路環境進行測試。

1、騰訊新聞

按照前面描述的推送適用場景,用這個騰訊新聞頁面(https://news.qq.com/a/20171031/032143.htm)做測試。主請求頁面大小為11.6K。可以看出,預先推送js、css、圖片等資源給客戶端帶來的網站性能變快。

圖11 騰訊新聞頁面

圖12 騰訊新聞頁面的無推送&推送對比圖

2、騰訊客服

騰訊客服頁面不支持HTTPS協議。之所以用這個頁面是因為該網頁頁面主請求比較小,並且有JS、CSS觸發的次優先順序資源請求。我們把這個網頁下載下來,並做了一些推送資源域名收歸等必要的處理,放在CDN邊緣節點做測試。這並沒有改變網站的資源和請求順序,不影響測試效果。

圖13 騰訊客服頁面

圖14 無推送&推送小文件&推送大文件的對比圖

5

總結

雖然本章的測試用例只是龐大互聯網網頁的冰山一角,文章不能覆蓋各種網頁場景。但是以下的一些總結建議是有實踐意義的。

1、在合適的時機,推送合適的資源,Push比No Push帶來的網站時延提升是明顯的。在網路帶寬足夠承載推送資源的前提下,我們預先推送瀏覽器後續請求需要的資源,網站的整體載入時間得到縮短。但是現實網路環境有不一樣的延時和帶寬。慢速網路環境影響TCP擁塞窗口增長的速度,除非主頁面請求足夠小,Push才能看到效果。

2、即使是錯誤地實施某些推送策略(比如說推送過大文件),帶來的最嚴重後果,也就是改善不明顯。所以建議是多做一些推送策略的嘗試,直到把合適的資源在合適的時機把資源推送給瀏覽器。

3、網站往HTTP/2的環境遷移是個趨勢。遷往HTTP/2需要將頁面的所有請求盡量收歸到同一域名,並且剝離出主頁面的資源文件成多個獨立的請求。假如你的網站已遷移到HTTP/2,而且網站的主請求不大,但是可能會觸發很多資源請求。建議push這些資源。另外不要推送存放在瀏覽器cookie的資源,這隻會浪費帶寬。

4、目前的Server Push推送機制沒有解決瀏覽器已經具有資源緩存,而伺服器已經推送到網路中,雖然瀏覽器可以發送RST楨拒絕推送流,但是伺服器推送的資源已經在網路中等待瀏覽器接收。現在已經有一些規範草案(https://tools.ietf.org/html/draft-kazuho-h2-cache-digest-01)嘗試用協商緩存摘要來解決問題。

5、CDN中的負載均衡機制可能會將低優先順序的推送資源送入到系統緩存區,這會影響高優先順序資源的推送效率問題。引入QUIC替代TCP,可以對緩存中推送資源進行分級,高優先順序資源先發。

6、未來或將引入AI分析取代固定推送實現智能化推送。

徵稿啦!

關注云加社區,回復3加讀者群


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雲加社區 的精彩文章:

遊戲開發者注意!這個音頻SDK可以完美兼容所有主流遊戲引擎
Python從小白到進階必備書單

TAG:雲加社區 |