摘要: 學習 HTTP/2 與 HTTP/3。html
Fundebug經受權轉載,版權歸原做者全部。前端
HTTP/2 相比於 HTTP/1,能夠說是大幅度提升了網頁的性能,只須要升級到該協議就能夠減小不少以前須要作的性能優化工做,固然兼容問題以及如何優雅降級應該是國內還不廣泛使用的緣由之一。git
雖然 HTTP/2 提升了網頁的性能,可是並不表明它已是完美的了,HTTP/3 就是爲了解決 HTTP/2 所存在的一些問題而被推出來的。github
HTTP協議是HyperText Transfer Protocol(超文本傳輸協議)的縮寫,它是互聯網上應用最爲普遍的一種網絡協議。全部的WWW文件都必須遵照這個標準。伴隨着計算機網絡和瀏覽器的誕生,HTTP1.0也隨之而來,處於計算機網絡中的應用層,HTTP是創建在TCP協議之上,因此HTTP協議的瓶頸及其優化技巧都是基於TCP協議自己的特性,例如tcp創建鏈接的3次握手和斷開鏈接的4次揮手以及每次創建鏈接帶來的RTT延遲時間。面試
request-response
對按序發生。顯然,若是某個請求長時間沒有返回,那麼接下來的請求就所有阻塞了。如上圖所示,紅色圈出來的請求就因域名連接數已超過限制,而被掛起等待了一段時間。小程序
由於HTTP/1.x的問題,咱們會引入雪碧圖、將小圖內聯、使用多個域名等等的方式來提升性能。不過這些優化都繞開了協議,直到2009年,谷歌公開了自行研發的 SPDY 協議,主要解決HTTP/1.1效率不高的問題。谷歌推出SPDY,纔算是正式改造HTTP協議自己。下降延遲,壓縮header等等,SPDY的實踐證實了這些優化的效果,也最終帶來HTTP/2的誕生。segmentfault
SPDY 協議在Chrome瀏覽器上證實可行之後,就被看成 HTTP/2 的基礎,主要特性都在 HTTP/2 之中獲得繼承。微信小程序
2015年,HTTP/2 發佈。HTTP/2是現行HTTP協議(HTTP/1.x)的替代,但它不是重寫,HTTP方法/狀態碼/語義都與HTTP/1.x同樣。HTTP/2基於SPDY3,專一於性能,最大的一個目標是在用戶和網站間只用一個鏈接(connection)。瀏覽器
HTTP/2由兩個規範(Specification)組成:緩存
HTTP/2 採用二進制格式傳輸數據,而非 HTTP 1.x 的文本格式,二進制協議解析起來更高效。 HTTP / 1 的請求和響應報文,都是由起始行,首部和實體正文(可選)組成,各部分之間以文本換行符分隔。HTTP/2 將請求和響應數據分割爲更小的幀,而且它們採用二進制編碼。
接下來咱們介紹幾個重要的概念:
HTTP/2 中,同域名下全部通訊都在單個鏈接上完成,該鏈接能夠承載任意數量的雙向數據流。每一個數據流都以消息的形式發送,而消息又由一個或多個幀組成。多個幀之間能夠亂序發送,根據幀首部的流標識能夠從新組裝。
在 HTTP/2 中引入了多路複用的技術。多路複用很好的解決了瀏覽器限制同一個域名下的請求數量的問題,同時也接更容易實現全速傳輸,畢竟新開一個 TCP 鏈接都須要慢慢提高傳輸速度。
你們能夠經過 該連接 直觀感覺下 HTTP/2 比 HTTP/1 到底快了多少。
在 HTTP/2 中,有了二進制分幀以後,HTTP /2 再也不依賴 TCP 連接去實現多流並行了,在 HTTP/2中:
這一特性,使性能有了極大提高:
如上圖所示,多路複用的技術能夠只經過一個 TCP 鏈接就能夠傳輸全部的請求數據。
在 HTTP/1 中,咱們使用文本的形式傳輸 header,在 header 攜帶 cookie 的狀況下,可能每次都須要重複傳輸幾百到幾千的字節。
爲了減小這塊的資源消耗並提高性能, HTTP/2對這些首部採起了壓縮策略:
例以下圖中的兩個請求, 請求一發送了全部的頭部字段,第二個請求則只須要發送差別數據,這樣能夠減小冗餘數據,下降開銷
Server Push即服務端能經過push的方式將客戶端須要的內容預先推送過去,也叫「cache push」。
能夠想象如下狀況,某些資源客戶端是必定會請求的,這時就能夠採起服務端 push 的技術,提早給客戶端推送必要的資源,這樣就能夠相對減小一點延遲時間。固然在瀏覽器兼容的狀況下你也可使用 prefetch。 例如服務端能夠主動把JS和CSS文件推送給客戶端,而不須要客戶端解析HTML時再發送這些請求。
服務端能夠主動推送,客戶端也有權利選擇是否接收。若是服務端推送的資源已經被瀏覽器緩存過,瀏覽器能夠經過發送RST_STREAM幀來拒收。主動推送也遵照同源策略,換句話說,服務器不能隨便將第三方資源推送給客戶端,而必須是通過雙方確認才行。
雖然 HTTP/2 解決了不少以前舊版本的問題,可是它仍是存在一個巨大的問題,主要是底層支撐的 TCP 協議形成的。
上文提到 HTTP/2 使用了多路複用,通常來講同一域名下只須要使用一個 TCP 鏈接。但當這個鏈接中出現了丟包的狀況,那就會致使 HTTP/2 的表現狀況反倒不如 HTTP/1 了。
由於在出現丟包的狀況下,整個 TCP 都要開始等待重傳,也就致使了後面的全部數據都被阻塞了。可是對於 HTTP/1.1 來講,能夠開啓多個 TCP 鏈接,出現這種狀況反到只會影響其中一個鏈接,剩餘的 TCP 鏈接還能夠正常傳輸數據。
那麼可能就會有人考慮到去修改 TCP 協議,其實這已是一件不可能完成的任務了。由於 TCP 存在的時間實在太長,已經充斥在各類設備中,而且這個協議是由操做系統實現的,更新起來不大現實。
基於這個緣由,Google 就更起爐竈搞了一個基於 UDP 協議的 QUIC 協議,而且使用在了 HTTP/3 上,HTTP/3 以前名爲 HTTP-over-QUIC,從這個名字中咱們也能夠發現,HTTP/3 最大的改造就是使用了 QUIC。
QUIC 雖然基於 UDP,可是在本來的基礎上新增了不少功能,接下來咱們重點介紹幾個QUIC新功能。
經過使用相似 TCP 快速打開的技術,緩存當前會話的上下文,在下次恢復會話的時候,只須要將以前的緩存傳遞給服務端驗證經過就能夠進行傳輸了。0RTT 建連能夠說是 QUIC 相比 HTTP2 最大的性能優點。那什麼是 0RTT 建連呢?
這裏面有兩層含義:
上圖左邊是 HTTPS 的一次徹底握手的建連過程,須要 3 個 RTT。就算是會話複用也須要至少 2 個 RTT。
而 QUIC 呢?因爲創建在 UDP 的基礎上,同時又實現了 0RTT 的安全握手,因此在大部分狀況下,只須要 0 個 RTT 就能實現數據發送,在實現前向加密的基礎上,而且 0RTT 的成功率相比 TLS 的會話記錄單要高不少。
雖然 HTTP/2 支持了多路複用,可是 TCP 協議終究是沒有這個功能的。QUIC 原生就實現了這個功能,而且傳輸的單個數據流能夠保證有序交付且不會影響其餘的數據流,這樣的技術就解決了以前 TCP 存在的問題。
同HTTP2.0同樣,同一條 QUIC鏈接上能夠建立多個stream,來發送多個HTTP請求,可是,QUIC是基於UDP的,一個鏈接上的多個stream之間沒有依賴。好比下圖中stream2丟了一個UDP包,不會影響後面跟着 Stream3 和 Stream4,不存在 TCP 隊頭阻塞。雖然stream2的那個包須要從新傳,可是stream三、stream4的包無需等待,就能夠發給用戶。
另外QUIC 在移動端的表現也會比 TCP 好。由於 TCP 是基於 IP 和端口去識別鏈接的,這種方式在多變的移動端網絡環境下是很脆弱的。可是 QUIC 是經過 ID 的方式去識別一個鏈接,無論你網絡環境如何變化,只要 ID 不變,就能迅速重連上。
TCP 協議頭部沒有通過任何加密和認證,因此在傳輸過程當中很容易被中間網絡設備篡改,注入和竊聽。好比修改序列號、滑動窗口。這些行爲有多是出於性能優化,也有多是主動攻擊。
可是 QUIC 的 packet 能夠說是武裝到了牙齒。除了個別報文好比 PUBLIC_RESET 和 CHLO,全部報文頭部都是通過認證的,報文 Body 都是通過加密的。
這樣只要對 QUIC 報文任何修改,接收端都可以及時發現,有效地下降了安全風險。
如上圖所示,紅色部分是 Stream Frame 的報文頭部,有認證。綠色部分是報文內容,所有通過加密。
QUIC協議有一個很是獨特的特性,稱爲向前糾錯 (Forward Error Correction,FEC),每一個數據包除了它自己的內容以外,還包括了部分其餘數據包的數據,所以少許的丟包能夠經過其餘包的冗餘數據直接組裝而無需重傳。向前糾錯犧牲了每一個數據包能夠發送數據的上限,可是減小了由於丟包致使的數據重傳,由於數據重傳將會消耗更多的時間(包括確認數據包丟失、請求重傳、等待新數據包等步驟的時間消耗)
假如說此次我要發送三個包,那麼協議會算出這三個包的異或值並單獨發出一個校驗包,也就是總共發出了四個包。當出現其中的非校驗包丟包的狀況時,能夠經過另外三個包計算出丟失的數據包的內容。固然這種技術只能使用在丟失一個包的狀況下,若是出現丟失多個包就不能使用糾錯機制了,只能使用重傳的方式了。
Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟件、百姓網等衆多品牌企業。歡迎你們免費試用!