怎樣把網站升級到http/2

人人網FED發表於2017-09-23

為什麼要升級到http/2呢?我們用Chrome的控制檯進行網站評測的時候,非http/2的網站會給一個建議:

意思是說要使用http/2,我之前只是聽過http/2的一些介紹,其實http/2已經來了。http/2最大的特點是使用多路複用,對同一個域的伺服器只建立一次TCP連線,載入多個資源,使用二進位制幀傳輸,同時會對http頭部進行壓縮。使用http2會比http/1.1更加地高效,因此筆者對部落格網站嘗試進行了升級。

1. 升級到HTTP/2

要求nginx的最低版本是1.10.0,openssl的最低版本是1.0.2,http/2在實現上基本上只支援https。筆者的系統是centos 7,用yum安裝的nginx是1.10.2,這個版本是可以的,但是系統的openssl是1.0.1,把系統的openssl update一下,變成1.0.2,但還是不可以。發現是因為nginx在編譯的時候指定的openssl是1.0.1的,所以即使升級了系統的openssl也是沒有用的,如下圖所示:

那怎麼升級呢?nginx官方提供了兩種方法,第一種是升級作業系統,第二種是從原始碼編譯新版本的nginx,我們用第二種方法。當前nginx最新的穩定版本是1.12.1,在伺服器上執行以下命令:

wget http://nginx.org/download/nginx-1.12.1.tar.gz # 下載
tar -zxvf nginx-1.12.1.tar.gz # 解壓
cd nginx-1.12.1
./configure # 確認系統環境,生成make檔案
make # 編譯
sudo make install #安裝複製程式碼

configure的時候後面可以帶引數,引數可以用原先老版本nginx的引數,包括安裝路徑之類的,這個可以通過執行nginx -V得到,使得新nginx的配置和老nginx一樣。如果configure提示缺一些庫的話就相應地做些安裝,基本上就是它提示的庫後面帶上devel,如以下提示:

./configure: error: the Google perftools module requires the Google perftools

library. You can either do not enable the module or install the library.

可安裝下面這個庫解決:

sudo yum install gperftools-devel複製程式碼

新安裝後的nginx的openssl版本就對了:

然後新增nginx配置,原本https的listen為:

listen 443 ssl;複製程式碼

現在在後面加上http2:

listen 443 ssl http2;複製程式碼

然後把nginx關了再開一下(因為新安裝了一個nginx,要先關一下再開),這個時候再用瀏覽器訪問,原本的http1.1:

就會變成http2:

有個細節是HTTP/2不叫2.0,這是故意的,因為1.x容易混淆,所以2的時候就不帶小版本號了,所以上面firefox的顯示其實是不對的。

整個傳輸模型如下圖所示(圖片來自nginx):

nginx和客戶端是HTTP/2,而nginx和業務服務還是HTTP/1.1,因為nginx的服務和業務服務通常是處於同一個內網,速度一般會很快,而nginx和客戶端的連線就不太可控了,如果業務服務本身支援HTTP/2,會更好。

然後我們先看一下傳輸的流量節省了多少,如下圖所示,載入一個頁面:

可以看到,HTTP 2在流量方面並沒有太大的改進,只減少了4kB(1%)的流量,下面我們再分析原因。HTTP 2的優勢還在於它的多路複用等方面。

2. HTTP/2的優勢

(1)多路複用

多路複用的意義在於可以用同一個連線傳輸多個資源,進而使得以前在http 1.1所做一些優化就沒有必要了,如:

a)使用雪碧圖技術,把多張小圖合成一張大圖,減少請求數;

b)合併JS和CSS,減少請求數。

因為在http 1.1時代,由於需要建立多個TCP連線,伺服器需要更多的執行緒來處理請求,同樣地,瀏覽器也需要,所以瀏覽器會限制同一個域的同時請求數,Chrome是限制6個,總連線數是17個,其它瀏覽器的個數有所浮動,但差不多,讀者可以這個網站測試自己所用的瀏覽器的限制情況。可以實際對比一下,http 1.1會讓資源排隊載入,如下圖所示:

但當我們開啟了http/2之後,個數幾乎沒有限制了,如下圖所示:

你會發現這些資源都是同時載入的,後面載入的資源不需要進行排隊。也就是說理論上頻寬有多大,就能傳多快。實際的效果在筆者的部落格網站上,用了一個頁面重複了5次,比較平均值,load時間只快了4%,在我這個例子並不是很明顯,但並不能代表HTTP 2沒什麼用,如果nginx和業務服務的連線也是http/2應該會更好。

這個傳輸模型是這樣的,如下圖所示(圖片來自谷歌開發者文件):

資料以幀(frame)的格式在同一個連線傳輸,並且服務還可以提前Push一些資源給客戶端。

(2)Server Push

在上面兩張載入圖可以看到第一個資源html沒載入之前,其它資源是不會開始載入的,因為它們是html觸發載入,如img標籤就會載入一張圖片,所以要等html下載和解析了才能載入其它資源,而http2可以讓服務先把其它很可能客戶端會請求的資源先push發給你,不用等到請求的時候再傳送,這樣可以提高頁面整體的載入速度。nginx官網說目前暫不支援Server Push,但可以下載一個http2的Node.js包寫個demo感受一下,如下程式碼:

response.push('/img/banner.png');複製程式碼

(3)報文頭壓縮和二進位制編碼

由於https傳輸的資料是加密的,無法用抓包工具觀察到這個過程,我們可以做些理論分析。

使用二進位制傳輸的好處在於它更接近於計算機儲存特點,傳統的文字流傳輸形式存在一些解析上的複雜性,如對訊息長度(Message Length)的解析要分為5種情況,詳見w3c,而使用二進位制方式則不存在這個問題。需要注意的是http/2的二進位制形式並沒有改變http/1.1的體系,只是把傳輸報文格式改了,如下圖所示:

上圖展示了兩個幀,一個頭部幀,還有一個資料幀。

而報文頭壓縮是這樣的,如下圖所示:

客戶端發了兩次請求,第一次請求有完整的http報文頭部,第二次請求的時候只有一個path的欄位不一樣,但是這次報文頭它只需要傳送一個path的欄位就好了,這樣就大大減少了傳送的量。這個的實現要求客戶端和服務同時維護一個報文頭表。上面提到的少了4kb的流量很可能是這個節省下來的。這個的意義還是很大的,因為動態請求有時候可能只需要傳送幾個位元組的資料,但卻需要傳送一個幾百個位元組的報文頭(500 ~ 800)。


最後一個問題,HTTP/2的相容性如何?如caniuse所示:

IE11只在windows10支援,Chrome/Safari/Firefox/Opera等瀏覽器只支援https的http/2。

如果瀏覽器不支援http/2會怎麼樣呢?也是能夠正常開啟的,為什麼呢?因為建立https連線的時候需要先握手,瀏覽器或者客戶端會傳送一個Client Hello的包,這個包裡面會說明它是否支援http2,如下圖所示:

nginx就能夠根據握手資訊決定是否使用http/2,如果客戶端不支援就使用http/1.1。這裡從一個側面知道為什麼瀏覽器需要使用https和服務支援ALPN了。


參考:

  1. Introduction to HTTP/2 - 谷歌開發者文件

  2. Why Everyone Should Be Moving To HTTP/2
  3. HTTP/2 Frequently Asked Questions

擴充套件:

  1. 為什麼要把網站升級到HTTPS
  2. https連線的前幾毫秒發生了什麼
  3. WebSocket與TCP/IP




相關文章