- 解析QUIC/HTTP3:未來互聯網的基石
- 劉準 陳保軍編著
- 2639字
- 2024-10-14 16:39:23
1.3 HTTP版本演化
超文本傳輸協議(Hypertext Transfer Protocol,HTTP)是互聯網上使用最多的協議,也是推動傳輸層進化的主要力量。

圖1-20 TLS更快發送數據的嘗試

圖1-21 TLS 1.3首次連接和恢復連接
1.3.1 HTTP1
1990年Tim Berners-Lee設計的萬維網(World Wide Web,WWW)包含三大基礎技術:命名方案URI(Uniform Resource Identifier,統一資源標識符),通信協議HTTP和用來表示信息的標記語言HTML(Hyper Text Markup Language,超文本標記語言),并于當年完成了第一個瀏覽器原型。對于萬維網的開創性貢獻使得他贏得了萬維網之父的稱號。
1991年,Tim Berners-Lee基于之前的設計和實現發表了定義HTTP的文章,其中定義的HTTP就是HTTP0.9(本書中HTTP/0.9簡寫為HTTP0.9)版本。在這篇文章中,HTTP分成了如下四個階段。
●連接:客戶端使用域名或者IP地址和端口號連接到服務器,服務器接收連接。
●請求:客戶端發送一個請求,請求內容是一個ASCII字符串,包含GET方法和請求文件的路徑,以CRLF(回車換行)結束。
●響應:響應是一個ASCII字符的字節流,內容是HTML格式的超文本,行之間以CRLF隔開。
●關閉連接:服務器將響應發送完后關閉連接。
HTTP0.9過程如圖1-22所示。

圖1-22 HTTP 0.9過程
HTTP0.9響應內容格式如圖1-23所示。

圖1-23 HTTP 0.9響應內容格式
HTTP0.9并不是一個標準,且僅支持簡單的請求響應,只能訪問簡單的文本文檔。隨著萬維網的發展,資源種類開始變得多樣化,HTTP也需要支持更復雜的表達方式。于是1996年5月,HTTP工作組(HTTP-WG)發布了RFC1945,這就是HTTP1(本書中HTTP/1.0簡寫為HTTP1)。HTTP1是一個信息性的RFC,總結了當時應用較廣泛的HTTP機制。
HTTP1中引入了請求頭和響應頭,請求時可以指定HTTP版本號、用戶代理、接收類型等,響應可以指明響應狀態、內容長度、內容類型等。HTTP1可以支持除HTML格式外的多種類型文件,比如圖像、純文本等,已經由超文本協議變成了超媒體協議。
另外,HTTP1在GET之外增加了POST和HEAD請求方法;增加了緩存,并使用Expire、If-Modified-Since、Last-Modified首部字段協助客戶端和中間件判斷緩存是否過期;響應增加了狀態碼,這是之前HTTP 0.9版本在HTTP層無法表示的信息。
HTTP1中的請求和響應仍然是ASCII碼字符流,但是請求可以是包含由CRLF分隔的多個行;響應由狀態開始,之后是首部字段的多個行,常見的如Content-Type(文件格式)、Content-Length(內容長度)等。HTTP1請求和響應分別如圖1-24和圖1-25所示。

圖1-24 HTTP1請求

圖1-25 HTTP1響應
在使用TCP連接方面,HTTP1與HTTP0.9一樣,在請求之前打開一條TCP連接,完成響應后關閉,一個TCP連接上只能完成一個請求和響應,如圖1-26所示。
從圖1-26可以看出,每個TCP連接只能完成一個請求和響應,在響應較小的情況下建立連接和關閉連接的代價較大。除此之外,TCP連接建立后的慢啟動也會影響效率。
1.3.2 HTTP1.1
1997年1月IETF發布了RFC 2068,這是HTTP第一個IETF官方標準。1999年6月,IETF發布RFC 2616更新了RFC 2068,對HTTP1.1(本書中HTTP/1.1簡為為HTTP1.1)做了一些改進。2014年,IETF發布了6個新的RFC(RFC 7230-7235)取代了RFC 2616,但并沒有大的修改。

圖1-26 HTTP1與TCP
HTTP1.1最大的改進在于增加了重用TCP連接的方法,默認保持連接,除非顯式通知關閉連接。這樣可以在一個TCP連接上完成多個請求-響應,消除了TCP建立的延遲,也避免了新建立的TCP連接的慢啟動過程。如圖1-27所示,HTTP1完成兩個請求-響應需要兩次TCP連接建立和關閉的過程,請求2-響應2還經過了TCP慢啟動;HTTP1.1在完成第一個請求后不關閉TCP連接,請求2-響應2可以直接在原來的TCP連接上進行。

圖1-27 HTTP1與HTTP1.1對比
保持連接的功能對性能非常重要,所以也移植到了HTTP1,HTTP1可以通過頭Connection:keep-alive來顯式通知保持連接。
另外,HTTP1.1在HTTP請求首部中增加了Host字段,用來支持共享IP地址的虛擬主機服務器;同時支持了更多的方法,如PUT、PATCH、DELETE、OPTIONS;引入分塊傳輸支持動態內容;引入了更多的緩存控制策略;支持請求部分內容等。HTTP1.1的請求響應過程如下。


雖然改善了之前版本的問題,但是HTTP1.1版本仍然存在一些問題導致帶寬利用率并不高。HTTP1.1多個請求-響應重用連接時,后面的請求-響應必須等前面的完成才能進行,這就導致了HTTP的頭部阻塞問題,即如果前面的請求-響應卡住了,后面的都無法進行。在一個TCP連接上,請求-響應只能一個一個排隊進行,效率比較低。所以,在使用HTTP1.1時,客戶端一般會建立多個TCP連接(比如大部分瀏覽器會控制到一個目的地的TCP連接個數為6),以便增加多個請求-響應的速度,減輕頭部阻塞問題。但是到一個目的地的多個TCP連接都會慢啟動,如果瀏覽器允許6個連接,但是需要執行300個請求,每個連接上平均有50個請求在排隊,有帶寬也不能發送,必須等前面請求的響應完成,這導致了用戶感知的時延的增加,并且有頭部阻塞的風險。另外TCP連接之間的競爭可能會導致丟包,從而出現大幅度的擁塞窗口減小,影響傳輸效率。
注意 HTTP1.1為了解決傳輸效率的問題,曾經提出過管道化傳輸,但效果不好,并沒有被廣泛采用。
1.3.3 HTTP2
為了解決HTTP1.1的問題,谷歌于2009年開始實驗性協議SPDY,主要目的是降低用戶感知到的延遲。
2012年,IETF開始基于SPDY進行HTTP2(本書中HTTP/2簡寫為HTTP2)版本的標準化,并于2015年5月發布了HTTP2標準RFC 7540。
HTTP2保留了HTTP1的語義,但修改了HTTP的封裝格式,增加了一個二進制分幀層。基于二進制分層,HTTP2實現了HTTP的多路復用。HTTP2為每個請求分配了一個流標識,服務器響應時帶上相同的流標識,客戶端就可以方便地將響應與請求關聯起來,而不用依賴順序,從而可以降低延遲和提高吞吐量。
通過多路復用,HTTP發送多個請求時就可以不用等待其他請求的響應(除優先級限制外),這樣可以充分利用帶寬,減少用戶感知到的延遲。如圖1-28所示,在帶寬充足的情況下,HTTP2客戶端比HTTP1.1可以更早地收到所有響應。

圖1-28 HTTP1.1與HTTP2對比
HTTP2不再使用人類可讀的字符串格式,而是采用二進制幀結構傳輸:

HTTP的首部和數據根據幀類型封裝成幀結構,在TCP+TLS上傳輸。由于幀內有流標識,可以將不同的請求使用不同的流標識發送,服務器回應時也可以根據流標識進行回應,客戶端收到幀就可以知道收到的響應對應哪個請求,從而做到多路復用,如圖1-29所示。

圖1-29 HTTP2多路復用
另外,HTTP2還增加了首部壓縮HPACK(Header Compression for HTTP2,HTTP2首部壓縮算法)以改善HTTP1首部字段在負載中占比過多的問題,支持請求優先級,支持服務器主動推送,增加了ALPN(Application-Layer Protocol Negotiation,應用層協議協商)。
HTTP2雖然實現了HTTP層的多路復用,但多個請求或響應在同一個TCP上發送時,仍然受制于TCP的隊首阻塞問題,無法進一步提高效率。以HTTP發送3個請求,但請求2所在TCP報文丟失為例:在TCP不支持SACK的情況下,服務器即使收到了請求3,TCP也會丟棄等重傳,無法處理請求2之后的請求,如圖1-30a所示;在TCP支持SACK的情況下,服務器收到了請求3,但因為是亂序報文,只能緩存不能交付給應用(這里應用指的是HTTP),所以也必須等請求2重傳后才能繼續處理之后的請求,如圖1-30b所示。

圖1-30 HTTP2的頭部阻塞:TCP不支持SACK和支持SACK
HTTP2支持認證、加密和完整性保護,這就是著名的HTTPS(Hypertext Transfer Protocol Secure,超文本傳輸安全協議),使用TCP+TLS發送一個請求的過程如圖1-31所示。

圖1-31 HTTP2使用TCP+TLS發送請求