Nginx 1.13.9:支持HTTP/2伺服器端推送
我們很高興地宣布,Nginx 1.13.9 於2018年2月20日正式發布,這個版本支持HTTP/2的伺服器端推送。對於Nginx PLUS的用戶,HTTP/2伺服器端推送的支持將包含在即將到來的 Nginx PLUS R15版本,這個版本預計於四月份發布。
伺服器端推送,是HTTP/2標準定義的功能。這個功能允許伺服器預判客戶端可能會用到的資源,並提前將資源推送給客戶端。這樣,我們就可以減少頁面載入時間,為用戶提供更流暢的體驗。
伺服器端推送可以為客戶端預先準備樣式表、圖片等頁面載入需要的文件。你需要仔細甄別哪些資源需要推送,盡量推送客戶端確實需要請求的,避免推送客戶端已經緩存的資源。
在這篇博文中,我們將描述:
HTTP/2伺服器端推送的基本配置
如何驗證HTTP/2伺服器端推送生效了(使用瀏覽器工具或者nghttp)
使用響應頭Link自動推送內容
選擇性推送內容
衡量HTTP/2伺服器推送的效果
配置HTTP/2伺服器端推送
要在頁面載入時推送資源,使用http2_push指令:
驗證HTTP/2伺服器端推送
你可以用下面兩種方法輕鬆地驗證伺服器端推送生效了:
瀏覽器的開發者工具
HTTP/2的命令行工具,比如nghttp
使用開發者工具驗證(以Google Chrome為例)
下面是如何使用瀏覽器的開發者工具驗證伺服器端推送是生效的,這裡使用Chrome作為例子。在下圖中,開發者工具中Network頁中的Initiator列顯示出我們通過伺服器端推送,將幾個資源伴隨對/demo.html的請求一同返回給了客戶端。
通過命令行工具驗證(nghttp)
除了瀏覽器的開發者工具,你還可以使用命令行工具nghttp來驗證伺服器端推送是有效的。你可以從github上下載並安裝nghttp,也可以使用操作系統的軟體包管理工具來安裝(比如在Ubuntu中,使用apt-get安裝nghttp2-client)。
圖中的星號代表資源是由伺服器端推送的。
自動推送資源給客戶端
很多時候,把需要推送的資源列舉在nginx配置中不是一個很好的做法。因此,Ngnix也支持解析Link預載入響應頭,然後自動推送響應頭中提到的資源。想要開啟預載入,在配置中開啟http2_push_preload指令。
比如,使用Nginx做請求代理(HTTP,FastCGI,或者其他請求類型)時,上游伺服器可以在返回的響應頭中增加一個Link欄位。
Nginx解析這個頭部欄位內容,並自動推送資源/style.css。Link欄位中的路徑必須是絕對路徑,可以帶查詢參數。
想要推送多個資源,你可以在頭部添加多個Link欄位,或者只用一個Link,但用逗號分隔多個資源說明。
如果你不想讓Nginx推送一個已經載入過的資源,向頭部加一個nopush參數
當http2_push_preload已經開啟,你也可以在nginx配置中添加Link響應頭來推送資源。
選擇性推送資源給客戶端
HTTP/2的標準中沒有解決什麼資源應該推送、什麼資源不需推送的問題。不過很顯然,推送的資源最好不是已經緩存過的內容,否則這次推送就沒有意義了。
一個可行的方案是,只在客戶端第一次訪問網站時推送資源。你可以在程序中檢查是否有該客戶端對應的session存在,只有在沒有session時才推送,換言之,也就是選擇性地推送資源。
假設客戶端設計良好,在首次之後的請求中都會攜帶session cookie,那麼這個方案就能保證每一個資源只在第一次請求時被推送一次。
測試伺服器端推送的效果
為了衡量伺服器端推送的效果,我們創建一個簡單的頁面/demo.html,它引用了一個獨立的css文件/style.css,這個css又引用了兩個圖片,我們使用三種不同的配置測試頁面載入的速度:HTTP, HTTPS, HTTP/2。
我們將進行多個測試:
HTTP使用多個GET請求請求資源,瀏覽器在發現需呀某個資源時再進行請求。
有preload標識的HTTP在第一次請求返回後得到preload標識,開始讓瀏覽器載入這些依賴資源。
HTTP/2的伺服器端推送會預先將資源直接推送給瀏覽器。
它們的行為是由Chrome的開發者工具衡量的。我們多次重複,取出每一種配置的典型性能,並根據RTT值(由ping得到)進行加權調整後得到下面的數據:
一些基本的觀察
建立HTTP鏈接需要一個RTT時間,建立HTTPS或者HTTP/2鏈接需要兩個RTT時間。
由於HTTP和CSS的資源體積小於一個MTU值,所以一個GET操作在一個RTT時間就可以完成。
當DOM loaded事件發生時,才真正地發起一個請求,來請求需要的資源。
解釋結果:預載入
伺服器推送為預載入減少了一個RTT時間,推送資源是在第一個請求返回時同步返回的,而preload預載入資源則需要額外花一個RTT的時間,其中第一個請求返回需要0.5個RTT,preload使用的GET請求到達需要0.5個RTT時間。
測試備註
我們進行了多次測量。每次測試開始時瀏覽器都沒有緩存,也沒有到nginx的keepalived鏈接。我們為nginx配置了keepalive_timeout和http2_idle_timeout,以便快速關閉keepalived鏈接。
無論使用preload標籤還是伺服器端推送,字體都無法有效地預載入,這是一個Chrome的已知問題。即便一個字體已經載入過了,Chrome還是會重複地請求字體資源。
需要注意的是,測試開始前一定要清楚緩存,並在返回的響應中設置緩存過期時間控制頭。
Chrome會緩存preload預載入的資源。即便你禁用緩存,這些緩存還是會生效,就算你明確地清除瀏覽器緩存,實際上緩存也不是每次都能被清除。Chrome有時也會不顧緩存地存在而去載入資源,這些載入請求在測試結果中我們已經剔除了。
我們手動設置了/etc/hosts,所以測試過程中不受DNS延遲的影響。
我們沒有測試在已經有緩存的情況下的效果。我們測試過程中,每次測試都是清除了緩存的,伺服器端推送進行得太快,根本沒機會在請求中中斷請求。
結論
這些測試都很簡單,主要用來講訴preload標籤和伺服器端推送的機制。在簡單的情形下,伺服器端推送相比於preload標籤,可以帶來一個RTT時間的優化,在很多未優化過的情境中,可能帶來的優化效果更明顯。
真實使用場景中有更多的變數。有更多可能用到的資源,也有更大的機會,會因為你錯誤地使用伺服器推送而浪費了帶寬。瀏覽器間的不一致也會影響最終的效果,你需要做的工作肯定比這個例子複雜得多。
比如,Chrome團隊撰寫了一個伺服器端推送配置推薦細則,他們在複雜的網站上測試了各種優化配置的效果。如果你想部署HTTP/2的伺服器端推送,那麼他們的報告《Rules of Thumb for HTTP/2 Push》非常值得一讀。
最後實際的結論就是,HTTP/2伺服器端推送讓你可以預先制定哪些資源需要推送載入,相比於返回一個preload提示,伺服器端推送有切實可見的性能提升。當然,錯誤的配置可能會導致你浪費帶寬,所以上線前請認真評估和檢查你的配置。
英文原文:https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/
譯者:詩書塞外


※【限量閃購】《決戰618》僅售55元包郵,只有兩本
※Python控制鍵盤滑鼠:pynput
TAG:Python程序員 |