HTTP2.0 原理詳解
影響一個網絡請求的因素主要有兩個,帶寬和延遲。今天的網絡基礎建設已經使得帶寬得到極大的提升,大部分時候都是延遲在影響響應速度。
連接無法復用
連接無法復用會導致每次請求都經歷三次握手和慢啟動。三次握手在高延遲的場景下影響較明顯,慢啟動則對文件類大請求影響較大。
head of line blocking
head of line blocking會導致帶寬無法被充分利用,以及後續健康請求被阻塞。
HTTP1.0 -> HTTP1.1
不過pipelining並不是救世主,它也存在不少缺陷:
pipelining只能適用於http1.1,一般來說,支持http1.1的server都要求支持pipelining
只有冪等的請求(GET,HEAD)能使用pipelining,非冪等請求比如POST不能使用,因為請求之間可能會存在先後依賴關系。
head of line blocking並沒有完全得到解決,server的response還是要求依次返回,遵循FIFO(first in first out)原則。也就是說如果請求1的response沒有回來,2,3,4,5的response也不會被送回來。
絕大部分的http代理服務器不支持pipelining。
和不支持pipelining的老服務器協商有問題。
可能會導致新的Front of queue blocking問題。
HTTP2 VS HTTP1.1
多路復用
多路復用通過多個請求stream共享一個tcp連接的方式,解決了http1.x holb(head of line blocking)的問題,降低了延遲同時提高了帶寬的利用率。
壓縮頭部
HTTP/2.0規定了在客戶端和服務器端會使用並且維護「首部表」來跟蹤和存儲之前發送的鍵值對,對於相同的頭部,不必再通過請求發送,只需發送一次。
事實上,如果請求中不包含首部(例如對同一資源的輪詢請求),那麽首部開銷就是零字節。此時所有首部都自動使用之前請求發送的首部。
如果首部發生變化了,那麽只需要發送變化了數據在Headers幀裏面,新增或修改的首部幀會被追加到“首部表”。首部表在 HTTP2.0的連接存續期內始終存在,由客戶端和服務器共同漸進地更新。
二進制分幀
在應用層與傳輸層之間增加一個二進制分幀層,以此達到“在不改動HTTP的語義,HTTP 方法、狀態碼、URI及首部字段的情況下,突破HTTP1.1的性能限制,改進傳輸性能,實現低延遲和高吞吐量。”
在二進制分幀層上,HTTP2.0會將所有傳輸的信息分割為更小的消息和幀,並對它們采用二進制格式的編碼,其中HTTP1.x的首部信息會被封裝到Headers幀,而我們的request body則封裝到Data幀裏面。
客戶端和服務器可以把HTTP消息分解為互不依賴的幀,然後亂序發送,最後再在另一端把它們重新組合起來。註意,同一鏈接上有多個不同方向的數據流在傳輸。客戶端可以一邊亂序發送stream,也可以一邊接收者服務器的響應,而服務器那端同理。
請求優先級
多路復用導致所有資源都是並行發送,那麽就需要「優先級」的概念了,這樣就可以對重要的文件進行先傳輸,加速頁面的渲染。
服務器推送
服務器推送是指在客戶端請求之前發送數據的機制。
另外有一點值得註意的是,客戶端如果退出某個業務場景,出於流量或者其它因素需要取消server push,也可以通過發送RST_STREAM類型的frame來做到。
HTTP2 實踐
這裏使用 Node.js 作為服務器端語言。
1. 生成TLS證書
如果想要在生產環境中使用HTTP2,那麽你可以去這裏生成一個證書。
如果你僅僅開發環境使用,那麽我們可以自己生成一個自簽名的TSL證書。
安裝OpenSSH
使用OpenSSH生成私鑰
openssl genrsa -des3 -passout pass:1234 -out server.pass.key 2048`
這裏
1234
為私鑰密碼,如果你不想使用密碼,則可以去除私鑰密碼,敲入如下密令:openssl rsa -passin pass:x -in server.pass.key -out server.key
創建 證書簽名請求
這裏使用無密碼私鑰,如果使用帶密碼私鑰,只需將server.key
更換為server.pass.key
即可,密令如下openssl req -new -key server.key -out server.csr
創建證書
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
通過以上四個步驟,我們得到了三個文件
server.key 你的TSL證書私鑰
server.csr 你的TSL證書簽名請求
server.crt 你的TSL證書
2. 使用Node.js 創建服務器
安裝 node-http2 模塊
npm install http2
創建服務器
var options = {
key: fs.readFileSync(‘./server.key‘),
cert: fs.readFileSync(‘./server.crt‘)
};
require(‘http2‘).createServer(options, function(request, response) {
response.end(‘Hello world!‘);
}).listen(8080);
啟動服務器
node index.js
使用瀏覽器訪問
http://localhost:8080
到此,一個簡單的Demo就完成了。
Demo源碼下載
點擊這裏訪問完整Demo
https://github.com/zhanyouwei...
測試結果對比
通過上面兩張截圖可以發現,使用了HTTP2後,同樣的請求,在數據傳輸大小與速度上都有非常大的提升,幾乎可以預見,不久的將來,HTTP2將會大放異彩。
HTTP2.0 原理詳解