HTTP 2 的新特性你 get 了嗎?

導語

HTTP/2 的主要設計思想應該都是源自 Google的 SPDY 協議,是互聯網工程任務組 ( IETF ) 對谷歌提出的 SPDY 協議進行標準化纔有了現在的 HTTP/2 。下面我們直奔主題分析 HTTP/2 的新特性,並且與 HTTP/1.x作對比。

一、多路複用的單一長連接

1.單一長連接

在HTTP/2中,客戶端向某個域名的服務器請求頁面的過程中,只會創建一條TCP連接,即使這頁面可能包含上百個資源。而之前的HTTP/1.x一般會創建6-8條TCP連接來請求這100多個資源。單一的連接應該是HTTP2的主要優勢,單一的連接能減少TCP握手帶來的時延(如果是建立在SSL/TLS上面,HTTP2能減少很多不必要的SSL握手,大家都知道SSL握手很慢吧)。

另外我們知道,TCP協議有個滑動窗口,有慢啓動這回事,就是說每次建立新連接後,數據先是慢慢地傳,然後滑動窗口慢慢變大,才能較高速度地傳,這下倒好,這條連接的滑動窗口剛剛變大,http1.x就創個新連接傳數據(這就好比人家HTTP2一直在高速上一直開着,你HTTP1.x是一輛公交車走走停停)。由於這種原因,讓原本就具有突發性和短時性的 HTTP 連接變的十分低效。

所以咯,HTTP2中用一條單一的長連接,避免了創建多個TCP連接帶來的網絡開銷,提高了吞吐量。

2.多路複用

明明是一條連接,怎麼又是多路複用呢?後臺開發的童鞋應該對多路複用很熟悉,例如用select,poll,epoll來管理一堆的fd,在這裏,HTTP2雖然只有一條TCP連接,但是在邏輯上分成了很多stream。這個特性又很關鍵吶。先看下面這個網上借用的圖 。

圖片來源:http://www.360doc.com/content/16/0120/09/30136251_529253725.shtml

以前的http1.x怎麼幹的?在一條TCP連接上,多個請求只能串行執行!你說咱們現在的網絡帶寬這麼大,這不浪費嗎?http2就不一樣了,不管多少請求,只要有,就往連接裏面扔好了,這能明顯降低一個頁面加載的時間。

HTTP2多路複用怎麼做到的?又來打個比方,你看高速公路,雖然路只有一條,但是收費的那個門是不是有很多個?

HTTP2把要傳輸的信息分割成一個個二進制幀,首部信息會被封裝到HEADER Frame,相應的request body就放到DATA Frame,一個幀你可以看成路上的一輛車,只要給這些車編號,讓1號車都走1號門出,2號車都走2號門出,就把不同的http請求或者響應區分開來了。但是,這裏要求同一個請求或者響應的幀必須是有有序的,要保證FIFO的,但是不同的請求或者響應幀可以互相穿插。這就是HTTP2的多路複用,是不是充分利用了網絡帶寬,是不是提高了併發度?

更進一步,http2還能對這些流(車道)指定優先級,優先級能動態的被改變,例如把CSS和JavaScript文件設置得比圖片的優先級要高,這樣代碼文件能更快的下載下來並得到執行。

現在回過頭來看下,請求一個包含幾十個或者幾百個資源的頁面,HTTP1.x和HTTP2在過程上面的區別,如下圖所示:

我想英文不捉雞的同學應該都能看懂,這裏http1.x建了6到8個tcp連接後,一個個請求串行地用這八個連接執行,而http2能一次把所有請求都發出去,還是壓縮過的,高下立判。

二、頭部壓縮和二進制格式

http1.x一直都是plain text,對此我只能想到一個優點,便於閱讀和debug。但是,現在很多都走https,SSL也把plain text變成了二進制,那這個優點也沒了。

於是HTTP2搞了個HPACK壓縮來壓縮頭部,減少報文大小(調試這樣的協議將需要curl這樣的工具,要進一步地分析網絡數據流需要類似Wireshark的http2解析器)。HPACK把報文中常見的字段名和值變成一個索引值index,也就是維護了一張靜態索引表,例如把 method: GET對應成索引表中index爲2的一個值,但是頭部還有一些不確定的東西,比如user-agent對應的瀏覽器名字啊。

所以它也維護了一個動態的索引表,靜態表索引值爲2-61,這時候數據傳輸過程中發現一個user-agent Mozilla/5.0,那就把這個追加到動態索引表值爲62的地方,這次開始就用62代替這個user-agent Mozilla/5.0,所以這個動態索引表是在數據傳輸過程中逐步建立的,靜態索引表寫死的。

此外,對於資源路徑這種完全不確定的東西,HPACK就採用Huffman編碼來壓縮,這樣三管齊下,頭部內容能大幅減少。可以看看下面的HPACK示意圖:

頭部爲什麼需要壓縮?

因爲一些重複東西在每個http請求裏面都有,例如method: GET。當一個客戶端從同一服務器請求一些資源(例如頁面的圖片)的時候,這些請求看起來幾乎是一致的。而這些大量一致的東西正好值得被壓縮

另外,HTTP 1.1請求的大小變得越來越大,有時甚至會大於TCP窗口的初始大小,這會嚴重拖累發送請求的速度。因爲它們需要等待帶着ACK的響應回來以後,才能繼續被髮送。尤其是當http請求內容超過TCP報文最大報文大小時,會被分成幾個TCP報文,這時候如果壓縮,能減少了tcp報文個數,就能減少幾個RTT時間了。

反過來,頭部壓縮也帶來了CPU消耗,而且如果剛好頭部能被裝到一個TCP報文裏面,壓縮也沒什麼卵用。而且大部分響應報文的body一般比header大很多,這時候好像壓縮頭部也是多此一舉。

三、服務端推送Server Push

這個功能通常被稱作“緩存推送”。主要的思想是:當一個客戶端請求資源X,而服務器知道它很可能也需要資源Z的情況下,服務器可以在客戶端發送請求前,主動將資源Z推送給客戶端。

這個功能幫助客戶端將Z放進緩存以備將來之需。服務器推送需要客戶端顯式的允許服務器提供該功能。但即使如此,客戶端依然能自主選擇是否需要中斷該推送的流。如果不需要的話,客戶端可以通過發送一個RST_STREAM幀來中止。

以上就是HTTP最主要的幾個新特性啦(當然還有很多新特性,這裏不詳談啦)。最後安利一下HTTP2 + SSL吧,貌似目前瀏覽器只有在服務器支持http2並且使用了SSL的時候纔會使用http2協議。總結一下爲什麼HTTP2能去掉SSL在HTTP1.x上的開銷?

1.單一的長連接,減少了SSL握手的開銷

2.頭部被壓縮,減少了數據傳輸量

3.多路複用能大幅提高傳輸效率,不用等待上一個請求的響應

4.不用像http1.x那樣把多個文件或者資源弄成一個文件或者資源(http1.x常見的優化手段),這時候,緩存就能更容易命中啊(http1.x裏面你揉成一團的東西怎麼命中緩存?)

哇。。寫文章真的累。但是有時間我還會再寫個nginx如何部署http2,以及做些實驗測試http2的性能。

此文已由作者授權騰訊雲技術社區發佈,轉載請註明文章出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章