何謂 http/2
(摘錄自「你的網站升級到 HTTP/2 了嗎?」)
隨著網頁內容越來越複雜,造成了要完成一個網頁載入(Page Load)的動作,除了要下載 HTML 之外,還需要下載 CSS 檔案、JavaScript 檔案、各種圖片檔案,零零總總加起來需要已經多達上百個對伺服器的 Request 請求資源,大大影響了網頁載入的速度。在這一秒鐘幾十萬上下的時代,Amazon 的網頁載入時間每多一秒,該公司的年度營收就減少 16 億美元、Google 的搜尋時間每多 0.4 秒,每天的搜尋次數就會減少 8 百萬網頁、KISSmetric 分析報告指出等待時間超過 4 秒,Bounce Rate 就會增加 25%。人的思緒在等 1 秒後就開始飄移,如果需要等 10 秒,就會感覺這東西是不是壞了。
這個問題的最大原因在於, HTTP/1.1 有一個非常大的缺陷是每個對伺服器的 Request 資源請求,都必須佔用一個網路連線(TCP connection),傳完一個檔案才能再傳下一個,瀏覽器無法同時下載。因此在 HTTP/1.1 時代,瀏覽器為了加速下載的時間,只好同時允許六個網路連線(TCP connection)併發去連接伺服器,好可以達成同時下載六個資源。但是極限也是如此了,並不是說無限制增加網路連線就可以解決這個瓶頸,因為每一次的網路連線,都必須經過三次握手的初始網路連線程序,而且每次初始連線因為流量控制的關係,一開始的網路封包會傳輸比較慢,後來才逐漸加快。
那麼,HTTP/2 是如何改良的呢?它採用的解法包括:
- 只需要單一網路連線(Single TCP connection),就可以連接網站伺服器,下載所有需要的資源。大大節省 HTTP/1.1 需要一直建立多個網路連線時的啟動時間浪費。
- 連線多工(Multiplexing),在單一網路連線上,就可以同時傳輸多個 HTTP Request 和 Response,併發請求 CSS/JS/Images 等等資源。它的原理是將 Requests/Responses 都拆碎成小 frames 進行傳輸,而這些 frames 是可以交錯的,因此檔案再多也不怕,不會發生佔用網路連線(TCP connection)的情況。這就是為什麼在圖檔多的情況下,HTTP/2 特別有優勢。
- 優先權設計(Prioritization),伺服器可以決定例如 CSS 或 JavaScript 檔案,哪些要優先傳送。
- Header 壓縮,在 HTTP/1.1 的 Headers 其實是沒有壓縮的,大小佔了約 200 bytes 到 2KB 不等,而且同一瀏覽器的每個 Requests 其實絕大部份的 Headers 都是重複的。HTTP/2 用了 HPACK 壓縮技術,大大減少每次都要重複傳輸一樣的 Headers。
- Binary 二進位的封包結構設計,對伺服器和瀏覽器來說,可以更快的解析這些資料。冷知識:在 HTTP/1.1 定義了四種解析訊息的方式,在 HTTP/2 只需要一種。
- 伺服器主動推送資源(Server Push),允許伺服器除了 HTML 之外,連同需要的 CSS/JavaScript/Images 檔案,主動推到瀏覽器的快取之中。不過,這個功能比較有爭議,一來他需要 Web 開發者額外描述有哪些檔案需要隨著 HTML 一起推送給瀏覽器,不是 Web 伺服器升級 HTTP/2 就自動會有。二來它不管瀏覽器是不是已經有快取這個資源,都會推送而造成頻寬浪費。因此實務上筆者認為可以改用瀏覽器的 Prefetch 功能,讓客戶端的瀏覽器自己處理即可。
透過這些技術,讓瀏覽器的網頁下載時間大大降低。而我們網站主需要做的,就是升級 Web 伺服器到支援 HTTP/2。
Ubuntu Apache 升級 http/2
Apache 網頁伺服器要使用 http/2,必須要是 TLS 也就是 https:// 模式,這一點學校大多數的網頁均已使用 Let's Encrypt SSL 進行加密了。還必須將預設的 mpm_prefork 模式改成 mem_event。PHP 也需要變成 fastcgi 模式執行 php-fpm
實際安裝情形:
sudo apt-get install php7.2-fpm
sudo a2enmod proxy_fcgi
sudo a2enconf php7.2-fpm
sudo a2dismod php7.2
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo a2enmod http2
sudo service apache2 restart
sudo service php7.2-fpm restart
還要在 site-enable 中關於 SSL 的網站設定檔中,在 <VirtualHost *:443> 後面加上一行「Protocols h2 h2c http/1.1」
Apache 和 php-fpm 重啟之後,用 phpinfo(); 檢查,出現 HTTP/2.0 便成功了。
參考資料:
留言
張貼留言