HTTP/2做錯了什么?剛剛輝煌2年就要被棄用了???
最近一段時間以來,關于HTTP/3的新聞有很多,越來越多的國際大公司已經(jīng)開始使用HTTP/3了。
所以,HTTP/3已經(jīng)是箭在弦上了,全面使用只是個時間問題,那么,作為一線開發(fā)者,我們也是時候了解下到底什么是HTTP/3,為什么需要HTTP/3了。
于是,我準備開始寫這篇文章,但是要想把HTTP/3的事情說清楚,一定繞不過的問題就是HTTP/2,所以寫著寫著,篇幅越來越多,于是我就把他們分成了上下兩篇。
這一篇我們主要來回顧下HTTP/2,然后再來重點看一下HTTP/2存在哪些問題,為什么要被棄用。
HTTP/2 輝煌不在?
雖然HTTP/2標準在2015年5月就以RFC 7540正式發(fā)表了,并且多數(shù)瀏覽器在2015年底就支持了。
但是,真正被廣泛使用起來要到2018年左右,但是也是在2018年,11月IETF給出了官方批準,認可HTTP-over-QUIC成為HTTP/3。
2018年的時候,我寫過一篇文章介紹《HTTP/2到底是什么?》,那時候HTTP/2還是個新技術,剛剛開始有軟件支持,短短兩年過去了,現(xiàn)在HTTP/3已經(jīng)悄然而至了。
根據(jù)W3Techs的數(shù)據(jù),截至2019年6月,全球也僅有36.5%的網(wǎng)站支持了HTTP/2。所以,可能很多網(wǎng)站還沒開始支持HTTP/2,HTTP/3就已經(jīng)來了。
所以,對于很多網(wǎng)站來說,或許直接升級HTTP/3是一個更加正確的選擇。
回顧 HTTP/2
在閱讀本文之前,強烈建議大家先閱讀下《HTTP/2到底是什么?》這篇文章,這里面介紹了HTTP的歷史,介紹了各個版本的HTTP協(xié)議的誕生的背景。
當你讀到這里的時候,我默認大家對HTTP/2有了一定的基本了解。
我們知道,HTTP/2的誕生,主要是為了解決HTTP/1.1中的效率問題,HTTP/2中最核心的技術就是多路復用技術,即允許同時通過單一的HTTP/2.0連接發(fā)起多重的請求-響應消息。
同時還實現(xiàn)了二進制分幀、header壓縮、服務端推送等技術。
從HTTP/1.0誕生,一直到HTTP/2,在這24年里,HTTP協(xié)議已經(jīng)做過了三次升級,但是有一個關鍵的技術點是不變的,那就是這所有的HTTP協(xié)議,都是基于TCP協(xié)議實現(xiàn)的。
流水的HTTP,鐵打的TCP。這是因為相對于UDP協(xié)議,TCP協(xié)議更加可靠。
雖然在HTTP/1.1的基礎上推出HTTP/2大大的提升了效率,但是還是有很多人認為這只是個"臨時方案",這也是為什么剛剛推出沒多久,業(yè)內就開始大力投入HTTP/3的研發(fā)與推廣了。
而這背后的深層次原因也正是因為他還是基于TCP協(xié)議實現(xiàn)的。TCP協(xié)議雖然更加可靠,但是還是存在著一定的問題,接下來具體分析下。
HTTP/2 問題
隊頭阻塞
隊頭阻塞翻譯自英文head-of-line blocking,這個詞并不新鮮,因為早在HTTP/1.1時代,就一直存在著隊頭阻塞的問題。
但是很多人在一些資料中會看到有論點說HTTP/2解決了隊頭阻塞的問題。但是這句話只對了一半。
只能說HTTP/2解決了HTTP的隊頭阻塞問題,但是并沒有解決TCP隊頭阻塞問題!
如果大家對于HTTP的歷史有一定的了解的話,就會知道。HTTP/1.1相比較于HTTP/1.0來說,最主要的改進就是引入了持久連接(keep-alive)。
所謂的持久連接就是:在一個TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲。
引入了持久連接之后,在性能方面,HTTP協(xié)議有了明顯的提升。
另外,HTTP/1.1允許在持久連接上使用請求管道,是相對于持久連接的又一性能優(yōu)化。
所謂請求管道,就是在HTTP響應到達之前,可以將多條請求放入隊列,當?shù)谝粭lHTTP請求通過網(wǎng)絡流向服務器時,第二條和第三條請求也可以開始發(fā)送了。在高時延網(wǎng)絡條件下,這樣做可以降低網(wǎng)絡的環(huán)回時間,提高性能。
但是,對于管道連接還是有一定的限制和要求的,其中一個比較關鍵的就是服務端必須按照與請求相同的順序回送HTTP響應。
這也就意味著,如果一個響應返回發(fā)生了延遲,那么其后續(xù)的響應都會被延遲,直到隊頭的響應送達。這就是所謂的HTTP隊頭阻塞。
但是HTTP隊頭阻塞的問題在HTTP/2中得到了有效的解決。HTTP/2廢棄了管道化的方式,而是創(chuàng)新性的引入了幀、消息和數(shù)據(jù)流等概念??蛻舳撕头掌骺梢园? HTTP 消息分解為互不依賴的幀,然后亂序發(fā)送,最后再在另一端把它們重新組合起來。
因為沒有順序了,所以就不需要阻塞了,就有效的解決了HTTP隊頭阻塞的問題。
但是,HTTP/2仍然會存在TCP隊頭阻塞的問題,那是因為HTTP/2其實還是依賴TCP協(xié)議實現(xiàn)的。
TCP傳輸過程中會把數(shù)據(jù)拆分為一個個按照順序排列的數(shù)據(jù)包,這些數(shù)據(jù)包通過網(wǎng)絡傳輸?shù)搅私邮斩?,接收端再按照順序將這些數(shù)據(jù)包組合成原始數(shù)據(jù),這樣就完成了數(shù)據(jù)傳輸。
但是如果其中的某一個數(shù)據(jù)包沒有按照順序到達,接收端會一直保持連接等待數(shù)據(jù)包返回,這時候就會阻塞后續(xù)請求。這就發(fā)生了TCP隊頭阻塞。
HTTP/1.1的管道化持久連接也是使得同一個TCP鏈接可以被多個HTTP使用,但是HTTP/1.1中規(guī)定一個域名可以有6個TCP連接。而HTTP/2中,同一個域名只是用一個TCP連接。
所以,在HTTP/2中,TCP隊頭阻塞造成的影響會更大,因為HTTP/2的多路復用技術使得多個請求其實是基于同一個TCP連接的,那如果某一個請求造成了TCP隊頭阻塞,那么多個請求都會受到影響。
TCP握手時長
一提到TCP協(xié)議,大家最先想到的一定是他的三次握手與四次關閉的特性。
因為TCP是一種可靠通信協(xié)議,而這種可靠就是靠三次握手實現(xiàn)的,通過三次握手,TCP在傳輸過程中可以保證接收方收到的數(shù)據(jù)是完整,有序,無差錯的。
但是,問題是三次握手是需要消耗時間的,這里插播一個關于網(wǎng)絡延遲的概念。
網(wǎng)絡延遲又稱為 RTT(Round Trip Time)。他是指一個請求從客戶端瀏覽器發(fā)送一個請求數(shù)據(jù)包到服務器,再從服務器得到響應數(shù)據(jù)包的這段時間。RTT 是反映網(wǎng)絡性能的一個重要指標。
我們知道,TCP三次握手的過程客戶端和服務器之間需要交互三次,那么也就是說需要消耗1.5 RTT。
另外,如果使用的是安全的HTTPS協(xié)議,就還需要使用TLS協(xié)議進行安全數(shù)據(jù)傳輸,這個過程又要消耗一個RTT(TLS不同版本的握手機制不同,這里按照最小的消耗來算)
那么也就是說,一個純HTTP/2的連接,需要消耗1.5個RTT,如果是一個HTTPS連接,就需要消耗3-4個RTT。
而具體消耗的時長根據(jù)服務器和客戶端之間的距離則不盡相同,如果比較近的話,消耗在100ms以內,對于用來說可能沒什么感知,但是如果一個RTT的耗時達到300-400ms,那么,一次連接建立過程總耗時可能要達到一秒鐘左右,這時候,用戶就會明顯的感知到網(wǎng)頁加載很慢。
升級TCP是否可行?
基于上面我們提到的這些問題,很多人提出來說:既然TCP存在這些問題,并且我們也知道這些問題的存在,甚至解決方案也不難想到,為什么不能對協(xié)議本身做一次升級,解決這些問題呢?
其實,這就涉及到一個"協(xié)議僵化"的問題。
這樣講,我們在互聯(lián)網(wǎng)上瀏覽數(shù)據(jù)的時候,數(shù)據(jù)的傳輸過程其實是極其復雜的。
我們知道的,想要在家里使用網(wǎng)絡有幾個前提,首先我們要通過運行商開通網(wǎng)絡,并且需要使用路由器,而路由器就是網(wǎng)絡傳輸過程中的一個中間設備。
中間設備是指插入在數(shù)據(jù)終端和信號轉換設備之間,完成調制前或解調后某些附加功能的輔助設備。例如集線器、交換機和無線接入點、路由器、安全解調器、通信服務器等都是中間設備。
在我們看不到的地方,這種中間設備還有很多很多,一個網(wǎng)絡需要經(jīng)過無數(shù)個中間設備的轉發(fā)才能到達終端用戶。
如果TCP協(xié)議需要升級,那么意味著需要這些中間設備都能支持新的特性,我們知道路由器我們可以重新?lián)Q一個,但是其他的那些中間設備呢?尤其是那些比較大型的設備呢?更換起來的成本是巨大的。
而且,除了中間設備之外,操作系統(tǒng)也是一個重要的因素,因為TCP協(xié)議需要通過操作系統(tǒng)內核來實現(xiàn),而操作系統(tǒng)的更新也是非常滯后的。
所以,這種問題就被稱之為"中間設備僵化",也是導致"協(xié)議僵化"的重要原因。這也是限制著TCP協(xié)議更新的一個重要原因。
所以,近些年來,由IETF標準化的許多TCP新特性都因缺乏廣泛支持而沒有得到廣泛的部署或使用!
放棄TCP?
上面提到的這些問題的根本原因都是因為HTTP/2是基于TPC實現(xiàn)導致的,而TCP協(xié)議自身的升級又是很難實現(xiàn)的。
那么,剩下的解決辦法就只有一條路,那就是放棄TCP協(xié)議。
放棄TCP的話,就又有兩個新的選擇,是使用其他已有的協(xié)議,還是重新創(chuàng)造一個協(xié)議呢?
看到這里,聰明的讀者一定也想到了,創(chuàng)造新的協(xié)議一樣會受到中間設備僵化的影響。近些年來,因為在互聯(lián)網(wǎng)上部署遭遇很大的困難,創(chuàng)造新型傳輸層協(xié)議的努力基本上都失敗了!
所以,想要升級新的HTTP協(xié)議,那么就只剩一條路可以走了,那就是基于已有的協(xié)議做一些改造和支持,UDP就是一個絕佳的選擇了。
總結
因為HTTP/2底層是采用TCP協(xié)議實現(xiàn)的,雖然解決了HTTP隊頭阻塞的問題,但是對于TCP隊頭阻塞的問題卻無能為力。
TCP傳輸過程中會把數(shù)據(jù)拆分為一個個按照順序排列的數(shù)據(jù)包,這些數(shù)據(jù)包通過網(wǎng)絡傳輸?shù)搅私邮斩?,接收端再按照順序將這些數(shù)據(jù)包組合成原始數(shù)據(jù),這樣就完成了數(shù)據(jù)傳輸。
但是如果其中的某一個數(shù)據(jù)包沒有按照順序到達,接收端會一直保持連接等待數(shù)據(jù)包返回,這時候就會阻塞后續(xù)請求。這就發(fā)生了TCP隊頭阻塞。
另外,TCP這種可靠傳輸是靠三次握手實現(xiàn)的,TCP三次握手的過程客戶端和服務器之間需要交互三次,那么也就是說需要消耗1.5 RTT。如果是HTTPS那么消耗的RTT就更多。
而因為很多中間設備比較陳舊,更新?lián)Q代成本巨大,這就導致TCP協(xié)議升級或者采用新的協(xié)議基本無法實現(xiàn)。
所以,HTTP/3選擇了一種新的技術方案,那就是基于UDP做改造,這種技術叫做QUIC。
那么問題來了,HTTP/3是如何使用的UDP呢?做了哪些改造?如何保證連接的可靠性?UDP協(xié)議就沒有僵化的問題了嗎?
這些問題我們在下一篇中深入分析。敬請期待!
參考資料:https://http3-explained.haxx.se/https://baike.baidu.com/item/中間設備/3688874https://time.geekbang.org/column/article/150159https://juejin.cn/post/6844903853985366023https://time.geekbang.org/column/article/279164