做者:盧滿宇, 騰訊後臺開發 工程師
商業轉載請聯繫騰訊WeTest得到受權,非商業轉載請註明出處。
原文連接:http://wetest.qq.com/lab/view/355.htmlcss
HTTP/1.X出色地知足互聯網的廣泛訪問需求,但隨着互聯網的不斷髮展,其性能愈來愈成爲瓶頸。IETF在2015年發佈了HTTP/2標準, 着重於提升HTTP的訪問體驗, HTTP2優點主要包括: 二進制傳輸、頭部壓縮、多路複用和服務器推送(Server Push)。 截止目前, 大部分CDN廠商已經宣佈支持HTTP/2,然而」支持」大多省略了服務器推送(ServerPush)特性。估計這和nginx開源版本沒有支持Server Push相關。爲提供完備的HTTP2能力,騰訊CDN現已完成HTTP/2的Server Push支持,並完成了詳細的性能測試。html
在介紹Server Push功能以前,先來分析網站的加載過程。圖1是騰訊課堂(https://ke.qq.com/index.html)...。nginx
a) 首先瀏覽器請求主頁面index.html,服務端響應內容;chrome
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正是基於此原理來提升網絡體驗。cookie
圖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/m...)。網頁上展現一張世界地圖,由400個小圖片組成。對比三種訪問方式:HTTP/1.一、HTTP/2(無Server Push)和 HTTP/2(Server Push)。Server Push選擇推送第150~179個共30個小圖。訪問性能數據對好比圖6所示:能夠發現預推送比無推送有必定的性能提高(受網絡延時和客戶端行爲影響,結果存在波動,後文有相應分析)。
圖6 demo網站測試
簡要介紹了Server Push的優化原理以後,伴隨而來的疑問,推送什麼資源,怎麼去推送,以及比其餘優化技術有什麼優點?讀完本章,這些問題將一一獲得解答,文章最後用實例展現Server Push的應用場景和性能優化效果。
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>; rel=preload; as=script;nopush。
用戶訪問CDN,主要包括直接訪問的邊緣節點, 若干中間節點和客戶源站,路徑中的每層均可以對請求作分析,預測可能的依賴資源,經過插入靜態標籤或者增長響應頭部返回給瀏覽器。 CDN的推送主要採用頭部攜帶推送信息。
a) 客戶端指定推送資源
客戶端經過url或者請求頭說明須要的資源url,寫法以下:
Url:http://http2push.gtimg.com/si...
或者:
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節點)能夠基於此信息進行資源請求與推送.
圖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相對應沒有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。
HTTP/1.1中有個資源內聯(Resource Inlining)技術,把資源內容拷貝到HTML標籤中。好比說<script>能夠裝載js的內容,<style>能夠裝載CSS的內容等。這樣JS或者CSS的內容就會在第一個響應中推送給瀏覽器。雖說它能夠作到網站加速。可是它有不少server push沒有的缺點。例如資源不能脫離HTML被瀏覽器單獨緩存,而且這個資源在多個url中重複傳輸多遍。這在多個url共享這個資源的場景是不明智的作法。而使用Server Push,在CDN能適用更豐富的應用場景。
理論上,在帶寬足夠的環境下,把須要的資源預先推送給客戶端,必然可以節省獲取資源時間,提高頁面訪問速度。但因爲TCP慢啓動、資源加載優先級、瀏覽器緩存等因素約束,咱們在實際測試中發現,Server Push並不總能帶來頁面加載性能的提高。本節深刻探討下什麼場景下的資源適合使用推送。
先複習下TCP慢啓動特性:爲了防止網絡擁塞,TCP將放棄超出擁塞窗口大小的數據。只有當擁塞串口大小的數據傳輸完成,這個窗口大小將乘以2。如此,可以傳輸的數據以2的倍數增加。假設擁塞窗口大小爲14kB,下圖展現了某些狀況下,推送比不推送的效率沒有提高。
其中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的效率更差。
HTTP/2的請求優先級並不能影響已經在內核發送緩衝區的數據。假設內核發送緩衝區大小比TCP擁塞串口大,致使服務端發送低優先級的數據,存在內核緩衝區。這時,後續有高優先級的響應必須等內核緩衝區空出才能被完成。假設咱們訪問一個HTML頁面,這個HTML頁面須要回源站取數據,而HTML須要的靜態JS資源緩存在CDN邊緣節點上。在回源站的等待時間內,把靜態JS資源發送給瀏覽器。若是這時候靜態JS資源很大,塞滿了內核發送緩衝區,此時HTML響應已經到達CDN邊緣節點,卻不得不等內核緩衝區有空間才能繼續發送。等待瀏覽器解析HTML內容後續的link請求也會被推遲。
推送瀏覽器已緩存的資源有可能使的加載時間更長,而且浪費帶寬資源。重複推送已緩存的資源,若是沒有額外的空閒帶寬傳輸,網絡會阻塞它以後正常的請求,致使拖累了整個網站的加載時間。
咱們對現網一些網頁進行Server Push性能測試,由於推送要求同一個域名下的HTTP/2請求,爲了規避非HTTP/2和跨餘名帶來的干擾,咱們設置了代理節點,代理節點完成HTTP/2支持和域名收歸,同時配置Server Push功能,觀察網頁的加載收益。爲了準確測試Push帶來網絡時延變化,須要穩定的網絡環境,在chrome設置網絡環境mytest(RTT: 200ms, Download: 29Mb/s, Upload: 14Mb/s),如下的例子都在該網絡環境進行測試。
按照前面描述的推送適用場景,用這個騰訊新聞頁面(https://news.qq.com/a/2017103...)作測試。主請求頁面大小爲11.6K。能夠看出,預先推送js、css、圖片等資源給客戶端帶來的網站性能變快。
圖11 騰訊新聞頁面
圖12 騰訊新聞頁面的無推送&推送對比圖
騰訊客服頁面不支持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 無推送&推送小文件&推送大文件的對比圖
雖然本章的測試用例只是龐大互聯網網頁的冰山一角,文章不能覆蓋各類網頁場景。可是如下的一些總結建議是有實踐意義的。
一、在合適的時機,推送合適的資源,Push比No Push帶來的網站時延提高是明顯的。在網絡帶寬足夠承載推送資源的前提下,咱們預先推送瀏覽器後續請求須要的資源,網站的總體加載時間獲得縮短。可是現實網絡環境有不同的延時和帶寬。慢速網絡環境影響TCP擁塞窗口增加的速度,除非主頁面請求足夠小,Push才能看到效果。
二、即便是錯誤地實施某些推送策略(好比說推送過大文件),帶來的最嚴重後果,也就是改善不明顯。因此建議是多作一些推送策略的嘗試,直到把合適的資源在合適的時機把資源推送給瀏覽器。
三、網站往HTTP/2的環境遷移是個趨勢。遷往HTTP/2須要將頁面的全部請求儘可能收歸到同一域名,而且剝離出主頁面的資源文件成多個獨立的請求。假如你的網站已遷移到HTTP/2,並且網站的主請求不大,可是可能會觸發不少資源請求。建議push這些資源。另外不要推送存放在瀏覽器cookie的資源,這隻會浪費帶寬。
四、目前的Server Push推送機制沒有解決瀏覽器已經具備資源緩存,而服務器已經推送到網絡中,雖然瀏覽器能夠發送RST楨拒絕推送流,可是服務器推送的資源已經在網絡中等待瀏覽器接收。如今已經有一些規範草案(https://tools.ietf.org/html/d...)嘗試用協商緩存摘要來解決問題。
五、CDN中的負載均衡機制可能會將低優先級的推送資源送入到系統緩存區,這會影響高優先級資源的推送效率問題。引入QUIC替代TCP,能夠對緩存中推送資源進行分級,高優先級資源先發。
六、將來或將引入AI分析取代固定推送實現智能化推送。
WeTest壓測大師——爲了幫助開發者發現服務器端的性能瓶頸,騰訊WeTest開放了壓力測試功能,經過基於真實業務場景和用戶行爲進行壓力測試,實現針對性的性能調優,下降服務器採購和維護成本。
壓測大師還服務了包括王者榮耀、龍之谷手遊、軒轅傳奇手遊、火影忍者等多款高星級手遊,也包括QQ、NOW直播等明星產品
目前壓測大師正式對外開放,點擊連接:http://wetest.qq.com/gaps/ 便可使用。
若是對使用當中有任何疑問,歡迎聯繫騰訊WeTest企業QQ:800024531