Http前世今生

現在開發者離不開網絡,所以都應該瞭解http協議以及它在整個網絡中所起的作用。知道了這些,對開發更好的應用起到很好的幫助作用。

下來,開始講述HTTP是什麼,它的由來,現在的發展以及它是如何走到這一步的。

這是一道填空題http://_________

HTTP是什麼?

HTTP(HyperText Transfer Protocol),名爲超文本傳輸協議。之所以叫超文本,是源於當時Tim Beners-Lee博士共享知識的設想,最初的理念是希望通過多文檔的互聯繼而形成超文本,連接可相互參閱的WWW(萬維網)。

HTTP是基於TCP/IP的應用層通信協議,它是客戶端和服務器之間相互通信的標準。它規定了如何在互聯網上請求和傳輸內容。通過應用層協議,我的意思是,它只是一個規範了主機(客戶端和服務器)如何通信的抽象層,並且它本身依賴於TCP/IP來獲取客戶端和服務器之間的請求和響應。默認的TCP端口是80端口,當然,使用其他端口也是可以的。比如,HTTPS使用的端口是443端口。

HTTP出生

自從在 1989-1991 年間被 CERN(譯註:即“歐洲核子研究組織”的原稱 - Conseil Européen pour la Recherche Nucléaire)的 Tim Berners-Lee 發明出來以後,HTTP(超文本傳輸協議) 就一直是萬維網的基礎傳輸協議。在 C/S 計算模型中,HTTP 起到了一個“請求/響應”協議的作用。HTTP 標準由 IETF(因特網工程任務組) 和 W3C(萬維網聯盟)負責開發,並以一系列註釋請求(RFCs - Requests for Comments)的形式被髮布。HTTP 有 4 個版本:HTTP/0.9、HTTP/1.0、HTTP/1.1 以及 HTTP/2.0。當前通常使用 HTTP/1.1 版本, HTTP/2.0 ,未來是 HTTP/3.0(quic)。

HTTP/0.9 - 極簡版(1991)

第一版的HTTP文檔是1991年提出來的 HTTP/0.9。這是有史以來最簡單的協議;它僅有一個GET方法。如果客戶端要訪問服務器上的一些網頁,它會作出如下的簡單請求:

image-20191012183826539

telnet xxx.com 80

(連接1建立 - TCP 三次握手)
Connected to xxx.xxx.xxx.xxx

(請求)
GET /my-page.html
並且來自服務器的響應內容如下:

(超文本響應)(response body)
<HTML>
A very simple HTML page
</HTML>

(connection closed)

也就是說,服務器會得到這個請求,然後通過HTML格式回覆響應內容,且一旦響應內容發送完畢,就會關閉這個連接。歸納一下:

  • 沒有header數據塊(無法傳輸其他內容類型的文件), 沒有 status/error 代碼, 沒有 URLs, 沒有版本控制
  • GET方法是唯一允許的方法
  • 必須以HTML格式響應,響應類型: 僅 超文本
  • 響應後馬上結束的連接

正如你所見,這個協議只不過是未來版本的一個墊腳石罷了。

HTTP/1.0 - 1996

1996年,HTTP的下一個版本,即 HTTP/1.0 誕生了,它在原版本上做出了極大的改善。不像 HTTP/0.9 僅能以HTML格式響應,HTTP/1.1 現在可以處理其他的響應格式了,例如:圖像,視頻文件,純文本或其他任何的內容類型。它增加了更多的方法(即 POST 和 HEAD),請求/響應的格式也發生了改變,請求和響應中均加入了HTTP頭信息,響應數據還增加了狀態碼標識,還介紹了字符集的支持、多部分發送、權限、緩存、內容編碼等很多內容。

構建可擴展性

  • 對瀏覽器友好的協議
  • 提供了對請求和響應都包含豐富元數據的 header 域 (HTTP 版本號、status code 和 content type)
  • 響應:不再只限於超文本 (Content-Type 頭部提供了傳輸 HTML 之外文件的能力 — 如腳本、樣式或媒體文件)
  • 支持的方法: GET , HEAD , POST
  • 響應後馬上結束的連接
  • session/cookie,解決無連接,無狀態的請求。

如下所示,這是一個通過 HTTP/1.0 請求和響應的例子:

GET / HTTP/1.0
Host: kamranahmed.info
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

正如你所見,客戶端除了發送請求以外,它還發送了它的個人信息,要求響應類型等。而在 HTTP/0.9 中因爲沒有頭信息,客戶端是不會發送這些信息的。

上面的例子對應的服務器響應結果如下:

HTTP/1.0 200 OK 
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

(response body)
(connection closed)

最開始的響應內容是 HTTP/1.0(HTTP後面的是版本號),然後是狀態碼200,再往後是原因短語(或狀態碼的描述)。

在這個新版本中,請求和響應的頭信息仍然採用 ASCII 編碼方式,但具體的響應內容可以是任何類型的,例如:圖像、視頻、HTML、純文本或任何其他的內容類型。因此,現在的服務器端可以向客戶端發送任何內容類型的數據;不久之後,HTTP介紹中的“超文本”術語就變得名不副實了。也許用HMTP或超媒體傳輸協議可能會更有意義一些,但是,我想,我們還是會一直用HTTP這個名字的。

HTTP/1.0的主要缺點之一是,你不能在每個連接中發送多個請求。也就是說,每當客戶端要向服務器端請求東西時,它都會打開一個新的TCP連接,並且在這個單獨請求完成後,該連接就會被關閉。且對於下個需求時,它必須再創建一個新的連接。爲什麼會如此糟糕呢?好吧,來讓我們做個假設,假設你需要訪問一個包含10張圖片、5個樣式表和5個JS文件的網頁,這是一個共20項內容要請求的網頁。由於服務器會在每個請求完成後將連接關閉,所以,這將會有一系列的20個獨立的連接,每個項目均有一個單獨的連接。因爲三次握手和其後的緩慢啓動機制,若每次請求都創建一個新的TCP連接,這就會帶來明顯的性能損失,最終的結果就是,這些大量的連接會導致嚴重的性能下降。

三次握手協議

HTTP/0.9 和 HTTP/1.0都需要爲每次請求建立一個新的連接(並在收到對應的響應後立即關閉該連接)。每次新連接建立時,都要經歷一遍 TCP 三次握手,並在開始共享應用數據之前會先共享一系列的數據包。

  • SYN - 客戶端創建一個隨機數(稱爲x),並且將x發送給服務器。
  • SYN ACK - 服務器確認請求後,當確認x是從客戶端發來時會發送一個ACK數據包(稱爲y,y=x+1)返回給客戶端。
  • ACK - 客戶端收到從服務器發來的增量y後,向服務器發送ACK(x+1)確認包。

當三次握手完成後,客戶端和服務器之間的數據共享就可以開始了。需要注意的是,客戶端可能會在處理完最後一個ACK數據包之後,就開始發送應用數據了。但服務器爲了完成請求,仍然需要等待ACK數據包收到才行。

image-20191012184239673

問題

然而,一些 HTTP/1.0 的實現試圖通過引入一個新的頭信息 Connection: keep-alive 來解決這個問題,這是爲了告訴服務器:“嘿,服務器,請不要關閉這個連接,我還要用它呢”。但這並沒有得到廣泛的支持,所以問題仍然存在。

除了是無連接的, HTTP 也是一個無狀態的協議,例如:服務器不會維護客戶端的信息,因此,在它自己與任何舊的請求沒有任何關聯的情況下,服務器爲了能完成請求,就需要每一個請求都必須帶有服務器所需要的信息才行。所以,這簡直就是“火上澆油”啊:客戶端除了要打開大量的連接,它還必須要發送一些冗餘的數據,這就導致了需要使用更多的帶寬。

HTTP/1.0+

在發佈 HTTP/1.0 之後,網絡飛速發展,很多流程web客戶端和服務器都在飛快地向HTTP中添加各種特性,以滿足快速擴張且在商業上十分成功的萬維網的需要。其中很多特性,包括keep-alive連接、虛擬機支持,以及代理連接支持都被加入到HTTP之中,併成爲非官方的事實標準。這種非正式的HTTP擴展版本稱爲 HTTP/1.0+。

HTTP/1.1 - 1999

HTTP/1.0僅發佈了3年之後,它的下一個版本,即HTTP/1.1便在1999年問世了,它在之前的基礎上做了很多的改進。基於HTTP/1.0的主要改進內容包含:

  • 這是當前普遍使用的 HTTP 版本
  • 進行了重大的性能優化和特性增強,分塊傳輸、壓縮/解壓、內容緩存磋商、虛擬主機(有單個 IP 地址的主機具有多個域名)、更快的響應,以及通過增加緩存節省了更多的帶寬
  • 新增的HTTP方法 PUT、PATCH、HEAD、OPTIONS、DELETE
  • 主機名標識 在 HTTP/1.0 中,Host頭信息不是必須項,但 HTTP/1.1 中要求必須要有Host頭信息。
  • 持久性連接 正如前面所說,在 HTTP/1.0 中每個連接只有一個請求 ,且在這個請求完成後該連接就會被關閉,從而會導致嚴重的性能下降及延遲問題。HTTP/1.1 引入了對持久性連接的支持,例如: 默認情況下連接不會被關閉,在多個連續的請求下它會保存連接的打開狀態。想要關閉這些連接,需要將 Connection: close 加入到請求的頭信息中。客戶端通常會在最後一次請求中發送這個頭信息用來安全的關閉連接。
  • 管道機制 HTTP/1.1也引入了對管道機制的支持,客戶端可以向服務器發送多個請求,而無需等待來自同一連接上的服務器響應,並且當收到請求時服務器必須以相同的順序來響應。但你可能會問:客戶端是怎麼知道第一個響應下載完成和下一個響應內容開始的?要解決這個問題,必須要有Content-Length頭信息,客戶端可以用它來確定響應結束,然後開始等待下一個響應。

http請求過程

(連接1建立 - TCP 三次握手)
Connected to xxx.xxx.xxx.xxx

(請求1)
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header

(響應1)
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding

[content]

(請求2)
GET /static/img/header-background.png HTTP/1.1
Host: developer.cdn.mozilla.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header

(響應2)
HTTP/1.1 200 OK
Age: 9578461
Cache-Control: public, max-age=315360000
Connection: keep-alive
Content-Length: 3077
Content-Type: image/png
Date: Thu, 31 Mar 2016 13:34:46 GMT
Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
Server: Apache

[image content of 3077 bytes]

(連接1關閉 - 斷掉 TCP)

性能優化和特性增強

應該注意的是,爲了從持久性連接或管道機制中獲益,Content-Length頭信息必須在可用的響應中,因爲這會讓客戶端知道當傳輸完成後,它可以發送下一個請求(用正常順序發送請求的方式)或者開始等待下一個響應(當啓用了管道機制時)。

但這種方法仍然存在一個問題:如果數據是動態的,且服務器找不到之前的內容長度時怎麼辦?那麼,在這種情況下,你就真的不能從持久性連接中收益了,不是嗎?!爲了解決這個問題,在 HTTP/1.1 中引入了分塊編碼的支持。在這種情況下,服務器可能會忽略 Content-Length 並支持分塊編碼。然而,如果他們沒有可用的數據,那麼連接必須在請求結束時關閉。

  • 分塊傳輸 在動態內容的情況下,當傳輸開始時服務器無法找到 Content-Length 頭信息的話,它也可以開始以塊的方式發送內容(一塊一塊的發),並且當每個小塊發送後,它會給每個塊添加一個 Content-Length 頭信息。當所有的塊發送完成後(即整個傳輸已經完成),它會發送一個空的塊(即 Content-Length 爲零的塊)以確定客戶端的傳輸已經完成。爲了通知客戶端採用分塊傳輸的方式,服務器需要在頭信息中包含Transfer-Encoding: chunked
  • 不像HTTP/1.0 只有基本的身份驗證,HTTP/1.1 還包含摘要和代理驗證
  • 高速緩存
  • 字節範圍
  • 字符集
  • 談判語言
  • 客戶端cookie
  • 加強對壓縮的支持
  • 新的狀態代碼
  • 以及更多。。。

1.0 vs 1.1

TCP 三次握手會在任何連接被建立之前發生一次。最終,當發送了所有數據之後,服務器發送一個消息,表示不會再有更多數據向客戶端發送了;則客戶端纔會關閉連接(斷開 TCP)。HTTP/1.0 存在的問題是,對於每個 請求/響應 輪迴,也要建立並關閉一個連接。而改用 HTTP/1.1 後的優點則在於,可以複用同一個連接,來完成多次 請求/響應 輪迴。

image-20191012184530602

pipeline

image-20191012184600502

特點

  • 管線化機制通過持久連接(persistent connection)完成,僅 HTTP/1.1 支持此技術(HTTP/1.0不支持)
  • 只有 GET 和 HEAD 請求可以進行管線化,而 POST 則有所限制
  • 初次創建連接時不應啓動管線機制,因爲對方(服務器)不一定支持 HTTP/1.1 版本的協議
  • 管線化不會影響響應到來的順序,如上面的例子所示,響應返回的順序並未改變
  • HTTP /1.1 要求服務器端支持管線化,但並不要求服務器端也對響應進行管線化處理,只是要求對於管線化的請求不失敗即可
  • 由於上面提到的服務器端問題,開啓管線化很可能並不會帶來大幅度的性能提升,而且很多服務器端和代理程序對管線化的支持並不好,因此現代瀏覽器如 Chrome 和 Firefox 默認並未開啓管線化支持
  • pipeline中有一個請求被卡住後面的請求都會被阻塞的隊頭阻塞問題

HTTP Pipelining是這樣一種技術:在等待上一個請求響應的同時,發送下一個請求。(譯者注:作者這個解釋並不完全正確,HTTP Pipelining其實是把多個HTTP請求放到一個TCP連接中一一發送,而在發送過程中不需要等待服務器對前一個請求的響應;只不過,客戶端還是要按照發送請求的順序來接收響應。)但就像在超市收銀臺或者銀行櫃檯排隊時一樣,你並不知道前面的顧客是乾脆利索的還是會跟收銀員/櫃員磨蹭到世界末日(譯者注:不管怎麼說,服務器(即收銀員/櫃員)是要按照順序處理請求的,如果前一個請求非常耗時(顧客磨蹭),那麼後續請求都會受到影響),這就是所謂的線頭阻塞(Head of line blocking)。

image-20191012184655683

即使在2019年的今天,大部分桌面瀏覽器也默認關閉了HTTP pipelining功能。

不足與缺陷

HTTP/1.1是在1999年發佈的,成爲標準有很多年了。 雖然它對上一版協議進行了很多改進,但web世界每天都在改變,它開始顯現出了它的不足。現在訪問的網頁與以前相比包含的資源更多。一個簡單的網頁都會至少打開30個連接。 我們知道 HTTP/1.1 是持久連接,那爲什麼還需要這麼多連接?你會說這是由於HTTP/1.1在任何時刻都只有一個有效連接。 HTTP/1.1嘗試通過pipeline來解決這個問題,但是它並沒有完全的解決,因爲在pipeline中有一個請求被卡住後面的請求都會被阻塞的隊頭阻塞問題。它將不得不等待下一個請求。 爲了克服HTTP/1.1的這些缺點, 開發人員開始嘗試一些解決方案,如:在CSS中使用雪碧圖、圖像編碼 ,合併CSS或Javascript文件, 域分片(將多個資源分別放入不同的子域名下)等等。

SPDY - 2009

Google走在前面,它開始試驗一種可替換的協議來減少網頁的延遲,使得網頁加載更快、提升web安全性 。 2009年, 他們稱這種協議爲SPDY。

SPDY是谷歌的一個商標,不是一個縮寫詞。

它們意識到如果繼續增加帶寬來提升網絡性能的過程中,必然在到達某一個點後不會再帶來更多提升。在有延遲的情況下如果我們不斷減少延遲,那麼性能將會是一個常數。這是 SPDY性能提升背後的核心理概念,減少延遲來提升網絡性能。

對於那些不知道這兩個概念的人, 延遲即數據從源傳輸到目標的耗時(以毫秒爲單位),帶寬就是每秒傳輸的數據量(比特/秒).

SPDY的功能包含: 多路複用, 壓縮, 優先級, 安全等。我不打算進入SPDY的細節,在進入下一節HTTP / 2後就會明白,HTTP / 2主要受SPDY的啓發。

SPDY 沒有真正試圖替換HTTP,它任然是存在於應用層的基於HTTP的傳輸層,它在請求發送前進行一些修改。 它開始成爲一個事實上的標準,大多數的瀏覽器開始實現它。

image-20191012184749127

2015年,谷歌不想存在兩個相互競爭的標準,因此他們決定把它合併到HTTP中成爲HTTP/2,同時放棄SPDY。

image-20191012184805377

HTTP/2 - 2015

現在,你已經知道我們爲什麼需要一個HTTP協議的修訂版了。 HTTP/2 是專爲低延遲傳輸的內容而設計。 關鍵特徵或與 HTTP / 1.1 舊版本的差異,如下:

  • 二進制,而不是文本
  • 多路複用- 在單個連接中多個異步HTTP請求
  • 使用HPACK報頭壓縮
  • 服務器推送 - 單請求多個響應
  • 請求優先級
  • 安全

image-20191012184830491

特點

  1. 二進制協議
    HTTP/2 傾向於使用二進制協議來減少HTTP/1.x中的延遲。二進制協議更容易解析,而不具有像HTTP/1.x 中那樣對人的可讀性。HTTP/2中的數據塊是: 幀和流。

    幀和流
    HTTP 消息是由一個或多個幀組成的。有一個叫做 HEADERS 的幀存放元數據,真正的數據是放在 DATA 幀中的,幀類型定義在the HTTP/2 specs(HTTP/2規範),如(HEADERS, DATA, RST_STREAM, SETTINGS, PRIORITY 等)。

    每個HTTP / 2請求和響應都被賦予一個唯一的流ID且放入了幀中。幀就是一塊二進制數據。 一系列幀的集合就稱爲流。 每個幀都有一個流id,用於標識它屬於哪一個流,每一個幀都有相同的頭。同時,除了流標識是唯一的,值得一提的是,客戶端發起的任何請求都使用奇數和服務器的響應是偶數的流id。

    除了 HEADERS和 DATA, 另外一個值得說一說幀類型是RST_STREAM,它是一個特殊的幀類型用於中止流,如:客戶端發送這幀來告訴服務器我不再需要這個流了。在 HTTP/1.1 中只有一種方式來實現服務器停止發送響應給客戶端,那就是關閉連接引起延遲增加,因爲後續的請求就需要打開一個新的連接。 在HTTP/2中,客戶端可以使用RST_FRAME來停止接收指定的流而不關閉連接且還可以在此連接中接收其它流。

  2. 多路複用
    由於HTTP / 2現在是一個二進制協議,且是使用幀和流來實現請求和響應,一旦TCP 連接打開了, 所有的流都通過這一連接來進行異步的發送而不需要打開額外的連接。反過來,服務器的響應也是異步的方式,如:響應是無序的、客戶端使用流id來標識屬於流的包。 這就解決了存在於HTTP/1.x 中head-of-line 阻塞問題,如: 客戶端將不必耗時等待請求,而其他請求將被處理。

  3. HPACK 頭部壓縮
    它是一個單獨的用於明確優化發送header RFC的一部分。它的本質是,當我們同一個客戶端不斷的訪問服務器時,在header中發送很多冗餘的數據,有時cookie 就增大header,且消耗帶寬和增加了延遲。爲了解決這個問題, HTTP/2 引入了頭部壓縮。

    與請求和響應不同,header不是使用的 gzip 或 compress等壓縮格式,它有不同的機制,它使用了霍夫曼編碼和在客戶端和服務器維護的頭部表來消除重複的 headers (如:user agent),在後續的請求中就只使用頭部表中引用。

    既然談到了header,那就再多說一點,它與HTTP/1.1中的一樣,不過增加了僞header,如: :method, :scheme,:host 和:path

    image-20191012184948837

  4. 服務器推送
    在服務器段,Server push是HTTTP/2的另外一個重要功能,我們知道,客戶端是通過請求來獲取資源的,它可以通過推送資源給客戶端而不需客戶端主動請求。 例如,瀏覽器載入了一個頁面,瀏覽器解析頁面時發現了需要從服務器端載入的內容,接着它就發送一個請求來獲取這些內容。

    Server push允許服務器推送數據來減少客戶端請求。 它是如何實現的呢,服務器在一個新的流中發送一個特殊的幀 PUSH_PROMISE,來通知客戶端:“嘿,我要把這個資源發給你!你就不要請求了。”

  5. 請求優先級
    客戶端可以在一個打開的流中在流的HEADERS 幀中放入優先級信息。 在任何時間,客戶端都可以發送一個PRIORITY 的幀來改變流的優先級。

    如果沒有優先級信息,服務器就會異步的處理請求,比如:無序處理。如果流被賦予了優先級,它就會基於這個優先級來處理,由服務器決定需要多少資源來處理該請求。

  6. 安全
    大家對HTTP/2是否強制使用安全連接(通過TLS)進行了充分的討論。最後的決定是不強制使用。 然而,大多數廠商表示,他們將只支持基於TLS的 HTTP / 2 。 所以,儘管HTTP / 2規範不需要加密,但它已經成爲默認的強制執行的。 在這種情況下,基於TLS實現的 HTTP/2需要的TLS版本最低要求是1.2。 因此必須有最低限度的密鑰長度,臨時密鑰等。

    HTTP/2超越了SPDY的變動也對它進行了增強。HTTP/2有很多性能提升,我們是時候開始使用它。

參考資料

HTTP2 即未來

HTTP2.0原理詳細解析

QUIC - 2013

基於SPDY原理,使用UDP快速網絡連接。

QUIC是快速UDP網絡連線(英語:Quick UDP Internet Connections)的縮寫,這是一種實驗性的傳輸層網絡傳輸協議,由Google公司開發,在2013年實現。QUIC使用UDP協議,它在兩個端點間創建連線,且支持多路複用連線。在設計之初,QUIC希望能夠提供等同於SSL/TLS層級的網絡安全保護,減少數據傳輸及創建連線時的延遲時間,雙向控制帶寬,以避免網絡擁塞。Google希望使用這個協議來取代TCP協議,使網頁傳輸速度加快,計劃將QUIC提交至互聯網工程任務小組(IETF),讓它成爲下一代的正式網絡規範。

  • QUIC(Quick UDP Internet Connections),直譯過來就是“快速的 UDP 互聯網連接”,是 Google 基於 UDP 提出的一種改進的通信協議,作爲傳統 HTTP over TCP 的替代品,開源於 Chromium 項目中。
  • 爲了加快 TCP 的傳輸效率,Google 提出了 BBR 擁塞控制算法,將 TCP 的性能發揮到了極致。由於 TCP 和 UDP 協議是系統內核實現的,要提出新的協議不是不行,只是普及起來會非常困難,就連 BBR 算法,都需要更新系統內核才能支持。那麼,TCP 的性能已經到了極致,還能更快嗎?
  • UDP 相比於 TCP,沒有那麼多的要求,只要將數據發出去就行了,不需要考慮數據是否送達了、不需要考慮數據的到達順序、不需要考慮數據的正確性和完整性,所以效率比 TCP 要高出幾個檔次。
  • UDP 協議曾經被普遍用於視頻直播、網絡遊戲之類實時性要求較高的應用,即使少數幾個包沒有送達對應用整體的影響也不大。可是,對於 HTTP 之類的協議,是需要保證數據的正確性、完整性的,所以 UDP 本身並不適合作爲 TCP 的替代品。
  • UDP 不適合替代 TCP 是因爲它本身不對數據進行校驗,那麼如果將數據校驗放到其他地方去實現,是不是就可以使用 UDP 了呢?
  • 於是,QUIC 就誕生了,它彙集了 TCP 和 UDP 的優點,使用 UDP 來傳輸數據以加快網絡速度,降低延遲,由 QUIC 來保證數據的順序、完整性和正確性,即使發生了丟包,也由 QUIC 來負責數據的 糾錯。

image-20191012185324469

QUIC 的優點

  1. 由於 TCP、UDP 協議是系統內核實現的,更新修改起來並不很方便,而 QUIC 是軟件層面實現的,更新迭代起來非常方便。
  2. UDP 本身是無序傳輸的,這在單個連接上並行傳輸多個數據有天生的優勢:多個數據直接發送即可,由 QUIC 對收到的數據進行重新組合排序,然後送往上層應用。這中間不用等待各種數據確認包,效率非常高。
  3. 在建立 TCP 連接時,需要進行至少三次握手,如果要開啓 TLS 加密,則還需要進行 TLS 握手。而 QUIC 採用了類似於 TCP Fast Open 的技術,如果之前連接過,那麼之後可以不用重複握手而直接開始傳送數據,以實現 0-RTT 往返時延。即便之前沒有連接過,也可以在 1-RTT 內完成連接並開始傳送數據。並且自身就擁有與 TLS 等效的加密措施。
  4. 在發生丟包時,TCP 會重傳丟失的包。而 QUIC,則使用了一種非常神奇的前向糾錯算法,通過連續的幾個數據包的校驗和,可以直接恢復出丟失的包內容,而不需要重傳。
  5. 在移動端表現更好:用戶的網絡環境並不穩定,Wi-Fi、4G、3G、2G 之間來回變化,IP 一旦發生變化,TCP 的連接是不可能保持的。而 QUIC 就不存在這樣的問題,通過 ID 來標識用戶(而不是 IP + 端口),在連接切換後直接恢復之前的連接會話。
  6. 配合 HTTP/2 API 食用更佳:由於 HTTP/2 採用二進制幀傳輸機制,QUIC 直接使用這樣的機制進行數據傳輸,效率更高!
  7. 一旦網絡異常,會導致TCP出現線頭阻塞(Head-of-line blocking),後續數據將被阻塞住;同時針對數據包重傳的會導致RTT延時測不太準。人們在使用HTTPS或HTTP/2時,可能因爲TLS協議層面一個記錄(record)丟失,導致後續其它的記錄一樣會被阻塞住,出現雙重阻塞,這基本上是無解的。TCP丟包阻塞機制導致無法實現真正的多路複用;而QUIC協議層面界定了流與流之間獨立的特性,就算是丟包,流與流之間也不會互相影響,實現了真正意義上的多路複用機制。

QUIC 的缺點

現在很多網絡運營商會降低 UDP 包的優先級,使得 UDP 丟包率特別高。(QUIC 不可用時,瀏覽器一般會 Fallback 到 TCP)

目前只有 Chrome、Opera 瀏覽器支持

什麼時候更適合使用 QUIC?

移動端
由於 QUIC 並不使用 IP + 端口來標識客戶身份,而是使用 ID,這使得在網絡環境切換後還可以保持連接,非常適合用在移動網站上面,在手機信號不穩定的情況下,TCP + TLS 的開銷是非常大的!QUIC 的 0-RTT 可以極大限度地提升訪問速度。

總結

QUIC 實現的目標,就是利用 UDP 實現一個 TCP,支持 TCP 的所有特性,並且比 TCP 更快更好用。
QUIC 是從 2012 年開始的項目,到目前也還只是草案階段,並且同樣處於草案階段的 TLS1.3 也同樣擁有了 QUIC 中的很多優點(比如 0-RTT)。對於訪問速度的優化方式越來越多,適當的選擇可以爲網站增色許多。

quic落地

QUIC在微博中的落地

騰訊雲落地

手機端落地

展望

http 協議發展迅速,和我們現在的技術生活息息相關。5G 的出現也促進了 http 協議的發展。

我們的生活會因爲技術的進步,越來越好!

如果你喜歡我的文章,可以關注我的掘金、公衆號、博客、簡書或者Github!

簡書: https://www.jianshu.com/u/a2591ab8eed2

GitHub: https://github.com/bugyun

Blog: https://ruoyun.vip

掘金: https://juejin.im/user/56cbef3b816dfa0059e330a8/posts

CSDN: https://blog.csdn.net/zxloveooo

歡迎關注微信公衆號

image

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