歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~
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 騰訊課堂域名的時間瀑布圖
圖2是簡化的瀏覽器和伺服器的互動過程,橫軸代表時間軸,每個虛線區間是1個RTT。紅色豎線表示DOM 載入完成的時間。從圖中可知,雖然存在併發傳輸, 但主頁index.html和依賴的資源common.css、0684a8bf.css、comb.nowrap.0b772fee.js等總體上是順序的,等待資源響應的時間減慢了主頁面載入速度。併發傳輸並不能提高序列解析的資源訪問體驗。
如果服務端接收到客戶端主請求,能夠“預測”主請求的依賴資源,在響應主請求的同時,主動併發推送依賴資源至客戶端。客戶端解析主請求響應後,可以”無延時”從本地快取獲取依賴資源, 減少訪問延時, 提高訪問體驗,也加大了鏈路的併發能力。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、標識依賴資源
W3C候選推薦標準(https://www.w3.org/TR/preload/)建議了依賴資源的兩種做法:檔案內標籤和HTTP頭部攜帶, 表示該資源後續會被使用, 可以預請求, 關鍵字preload修飾這個資源, 寫法如下:
a) 靜態Link標籤法:
b) HTTP頭表示法:
Link: <push.css>; rel=preload; as=style
其中rel表明了資源</push.css>是預載入的,as表明了資源的檔案型別。另外,link還可以用nopush修飾,表示瀏覽器可能已經有該資源快取,指示有推送能力的服務端不主動推送資源,只有當瀏覽器先檢查到沒有快取,才去指示服務端推送資源,nopush格式寫成:
Link: </app/script.js>; rel=preload; as=script;nopush。
2、推送資源
使用者訪問CDN,主要包括直接訪問的邊緣節點, 若干中間節點和客戶源站,路徑中的每層都可以對請求做分析,預測可能的依賴資源,通過插入靜態標籤或者增加響應頭部返回給瀏覽器。 CDN的推送主要採用頭部攜帶推送資訊。
a) 客戶端指定推送資源
客戶端通過url或者請求頭說明需要的資源url,寫法如下:
Url:http://http2push.gtimg.com/simple_push.html?req-push=simple_push.js
或者:
GET /simple_push.html HTTP/1.1
Host: http2push.gtimg.com
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 推送時間點位於主頁面響應之前
二
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)<BDP,推薦使用push;反之不推薦使用push。
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、瀏覽器快取
推送瀏覽器已快取的資源有可能使的載入時間更長,並且浪費頻寬資源。重複推送已快取的資源,如果沒有額外的空閒頻寬傳輸,網路會阻塞它之後正常的請求,導致拖累了整個網站的載入時間。
四
網站測試
我們對現網一些網頁進行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列出騰訊客服頁面的所有請求。我們關注下具體幾種情況的時間軸:無推送、推送小檔案、推送大檔案。小檔案推送預先在第一個RTT把3個第3層請求才能觸發的資源(tcss.ping.js、cdn_djl.js、layer.css)預先推送給瀏覽器。大檔案推送是預先推送了indexBanner.png。
從圖14中的無推送和推送3個小檔案的子圖中,紅色虛豎線是指不包括indexBanner.png的載入完成時間,由於3個小檔案(尤其是次優先順序請求tcss.ping.js)的提取推送,比無推送的時間延遲要短。但是又從無推送和推送大檔案的子圖中看到,如果無優先順序順序地推送大檔案indexBanner.png(782KB)對縮短網站時延無幫助。
圖13 騰訊客服頁面
圖14 無推送&推送小檔案&推送大檔案的對比圖
五
總結
雖然本章的測試用例只是龐大網際網路網頁的冰山一角,文章不能覆蓋各種網頁場景。但是以下的一些總結建議是有實踐意義的。
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分析取代固定推送實現智慧化推送。
問答
相關閱讀
此文已由作者授權騰訊雲+社群釋出,原文連結:https://cloud.tencent.com/developer/article/1159626?fromSource=waitui
歡迎大家前往騰訊雲+社群或關注雲加社群微信公眾號(QcloudCommunity),第一時間獲取更多海量技術實踐乾貨哦~
海量技術實踐經驗,盡在雲加社群!