HTTP/3正式發(fā)布,深入理解HTTP/3協(xié)議

經(jīng)過(guò)了多年的努力,在 6 月 6 號(hào),IETF (互聯(lián)網(wǎng)工程任務(wù)小組) 正式發(fā)布了 HTTP/3 的 RFC, 這是超文本傳輸協(xié)議(HTTP)的第三個(gè)主要版本,完整的 RFC 超過(guò)了 20000 字,非常詳細(xì)的解釋了 HTTP/3。

HTTP 歷史


1991 HTTP/1.1 2009 Google 設(shè)計(jì)了基于TCP的SPDY 2013 QUIC 2015 HTTP/2 2018 HTTP/3
HTTP2協(xié)議雖然大幅提升了HTTP/1.1的性能,然而,基于TCP實(shí)現(xiàn)的HTTP2遺留下3個(gè)問(wèn)題:
有序字節(jié)流引出的隊(duì)頭阻塞(Head-of-line blocking),使得HTTP2的多路復(fù)用能力大打折扣;
TCP與TLS疊加了握手時(shí)延,建鏈時(shí)長(zhǎng)還有1倍的下降空間;
基于TCP四元組確定一個(gè)連接,這種誕生于有線網(wǎng)絡(luò)的設(shè)計(jì),并不適合移動(dòng)狀態(tài)下的無(wú)線網(wǎng)絡(luò),這意味著IP地址的頻繁變動(dòng)會(huì)導(dǎo)致TCP連接、TLS會(huì)話(huà)反復(fù)握手,成本高昂。
HTTP3協(xié)議解決了這些問(wèn)題:
HTTP3基于UDP協(xié)議重新定義了連接,在QUIC層實(shí)現(xiàn)了無(wú)序、并發(fā)字節(jié)流的傳輸,解決了隊(duì)頭阻塞問(wèn)題(包括基于QPACK解決了動(dòng)態(tài)表的隊(duì)頭阻塞);
HTTP3重新定義了TLS協(xié)議加密QUIC頭部的方式,既提高了網(wǎng)絡(luò)攻擊成本,又降低了建立連接的速度(僅需1個(gè)RTT就可以同時(shí)完成建鏈與密鑰協(xié)商);
HTTP3 將Packet、QUIC Frame、HTTP3 Frame分離,實(shí)現(xiàn)了連接遷移功能,降低了5G環(huán)境下高速移動(dòng)設(shè)備的連接維護(hù)成本。

QUIC 協(xié)議概覽


QUIC是用來(lái)替代TCP, SSL/TLS的傳輸層協(xié)議, 在傳輸層之上還有應(yīng)用層. 我們熟知的應(yīng)用層協(xié)議有HTTP, FTP, IMAP等, 這些協(xié)議理論上都可以運(yùn)行在QUIC上, 其中運(yùn)行在QUIC之上的協(xié)議被稱(chēng)為HTTP/3, 這就是HTTP over QUIC即HTTP/3的含義,因此想要了解HTTP/3, QUIC是繞不過(guò)去的, 下面是幾個(gè)重要的QUIC特性.
0 RTT建立連接
RTT: round-trip time, 僅包括請(qǐng)求訪問(wèn)來(lái)回的時(shí)間

HTTP/3首次連接只需要1RTT, 后面的鏈接只需要0RTT, 意味著客戶(hù)端發(fā)送給服務(wù)端的第一個(gè)包就帶有請(qǐng)求數(shù)據(jù), 其主要連接過(guò)程如下:
首次連接, 客戶(hù)端發(fā)送Inchoate Client Hello, 用于請(qǐng)求連接; 服務(wù)端生成g, p, a, 根據(jù)g, p, a算出A, 然后將g, p, A放到Server Config中在發(fā)送Rejection消息給客戶(hù)端. 客戶(hù)端接收到g,p,A后, 自己再生成b, 根據(jù)g,p,a算出B, 根據(jù)A,p,b算出初始密鑰K, B和K算好后, 客戶(hù)端會(huì)用K加密HTTP數(shù)據(jù), 連同B一起發(fā)送給服務(wù)端. 服務(wù)端接收到B后, 根據(jù)a,p,B生成與客戶(hù)端同樣的密鑰, 再用這密鑰解密收到的HTTP數(shù)據(jù). 為了進(jìn)一步的安全(前向安全性), 服務(wù)端會(huì)更新自己的隨機(jī)數(shù)a和公鑰, 在生成新的密鑰S, 然后把公鑰通過(guò)Server Hello發(fā)送給客戶(hù)端. 連同Server Hello消息, 還有HTTP返回?cái)?shù)據(jù).

這里使用DH密鑰交換算法, DH算法的核心就是服務(wù)端生成a,g,p3個(gè)隨機(jī)數(shù), a自己持有, g和p要傳輸給客戶(hù)端, 而客戶(hù)端會(huì)生成b這1個(gè)隨機(jī)數(shù), 通過(guò)DH算法客戶(hù)端和服務(wù)端可以算出同樣的密鑰. 在這過(guò)程中a和b并不參與網(wǎng)絡(luò)傳輸, 安全性大大提升. 因?yàn)閜和g是大數(shù), 所以即使在網(wǎng)絡(luò)傳輸中p, g, A, B都被劫持, 靠現(xiàn)在的計(jì)算力算力也無(wú)法破解.
連接遷移
隊(duì)頭阻塞/多路復(fù)用
TCP是個(gè)面向連接的協(xié)議, 即發(fā)送請(qǐng)求后需要收到ACK消息, 以確認(rèn)對(duì)象已接受數(shù)據(jù). 如果每次請(qǐng)求都要在收到上次請(qǐng)求的ACK消息后再請(qǐng)求, 那么效率無(wú)疑很低. 后來(lái)HTTP/1.1提出了Pipeline技術(shù), 允許一個(gè)TCP連接同時(shí)發(fā)送多個(gè)請(qǐng)求. 這樣就提升了傳輸效率.

在這樣的背景下, 隊(duì)頭阻塞發(fā)生了. 比如, 一個(gè)TCP連接同時(shí)傳輸10個(gè)請(qǐng)求, 其中1,2,3個(gè)請(qǐng)求給客戶(hù)端接收, 但是第四個(gè)請(qǐng)求丟失, 那么后面第5-10個(gè)請(qǐng)求都被阻塞. 需要等第四個(gè)請(qǐng)求處理完畢后才能被處理. 這樣就浪費(fèi)了帶寬資源.
因此, HTTP一般又允許每個(gè)主機(jī)建立6個(gè)TCP連接, 這樣可以更加充分的利用帶寬資源, 但每個(gè)連接中隊(duì)頭阻塞的問(wèn)題還是存在的.
Frame通過(guò)一條TCP連接同時(shí)被傳輸, 這樣即使一個(gè)請(qǐng)求被阻塞, 也不會(huì)影響其他的請(qǐng)求.
但是, HTTP/2雖然可以解決請(qǐng)求這一粒度下的阻塞, 但HTTP/2的基礎(chǔ)TCP協(xié)議本身卻也存在隊(duì)頭阻塞的問(wèn)題. HTTP/2的每個(gè)請(qǐng)求都會(huì)被拆分成多個(gè)Frame, 不同請(qǐng)求的Frame組合成Stream, Stream是TCP上的邏輯傳輸單元, 這樣HTTP/2就達(dá)到了一條連接同時(shí)發(fā)送多個(gè)請(qǐng)求的目標(biāo), 其中Stram1已經(jīng)正確送達(dá), Stram2中的第三個(gè)Frame丟失, TCP處理數(shù)據(jù)是有嚴(yán)格的前后順序, 先發(fā)送的Frame要先被處理, 這樣就會(huì)要求發(fā)送方重新發(fā)送第三個(gè)Frame, Steam3和Steam4雖然已到達(dá)但卻不能被處理, 那么這時(shí)整條鏈路都會(huì)被阻塞.


QUIC的傳輸單位是Packet, 加密單元也是Packet, 整個(gè)加密, 傳輸, 解密都基于Packet, 這就能避免TLS的阻塞問(wèn)題. QUIC基于UDP, UDP的數(shù)據(jù)包在接收端沒(méi)有處理順序, 即使中間丟失一個(gè)包, 也不會(huì)阻塞整條連接. 其他的資源會(huì)被正常處理.
擁塞控制
慢啟動(dòng): 發(fā)送方像接收方發(fā)送一個(gè)單位的數(shù)據(jù), 收到確認(rèn)后發(fā)送2個(gè)單位, 然后是4個(gè), 8個(gè)依次指數(shù)增長(zhǎng), 這個(gè)過(guò)程中不斷試探網(wǎng)絡(luò)的擁塞程度. 避免擁塞: 指數(shù)增長(zhǎng)到某個(gè)限制之后, 指數(shù)增長(zhǎng)變?yōu)榫€性增長(zhǎng) 快速重傳: 發(fā)送方每一次發(fā)送都會(huì)設(shè)置一個(gè)超時(shí)計(jì)時(shí)器, 超時(shí)后認(rèn)為丟失, 需要重發(fā) 快速恢復(fù): 在上面快速重傳的基礎(chǔ)上, 發(fā)送方重新發(fā)送數(shù)據(jù)時(shí), 也會(huì)啟動(dòng)一個(gè)超時(shí)定時(shí)器, 如果收到確認(rèn)消息則進(jìn)入擁塞避免階段, 如果仍然超時(shí), 則回到慢啟動(dòng)階段.
1. 熱插拔
2. 前向糾錯(cuò) FEC
QUIC使用前向糾錯(cuò)(FEC, Forword Error Correction)技術(shù)增加協(xié)議的容錯(cuò)性. 一段數(shù)據(jù)被切分為10個(gè)包后, 一次對(duì)每個(gè)包進(jìn)行異或運(yùn)算, 運(yùn)算結(jié)果會(huì)作為FEC包與數(shù)據(jù)包一起被傳輸, 如果傳輸過(guò)程中有一個(gè)數(shù)據(jù)包丟失, 那么就可以根據(jù)剩余9個(gè)包以及FEC包推算出丟失的那個(gè)包的數(shù)據(jù), 這樣就大大增加了協(xié)議的容錯(cuò)性.
這是符合現(xiàn)階段網(wǎng)絡(luò)傳輸技術(shù)的一種方案, 現(xiàn)階段帶寬已經(jīng)不是網(wǎng)絡(luò)傳輸?shù)钠款i, 往返時(shí)間才是, 所以新的網(wǎng)絡(luò)傳輸協(xié)議可以適當(dāng)增加數(shù)據(jù)冗余, 減少重傳操作.

3. 單調(diào)遞增的Packer Number
Sequence Number和ACK來(lái)確認(rèn)消息是否有序到達(dá), 但這樣的設(shè)計(jì)存在缺陷.RTT: Round Trip Time, 往返事件 RTO: Retransmission Timeout, 超時(shí)重傳時(shí)間

QUCI解決了上面的的歧義問(wèn)題, 與Sequence Number不同, Packet Number嚴(yán)格單調(diào)遞增, 如果Packet N丟失了, 那么重傳時(shí)Packet的標(biāo)識(shí)就不會(huì)是N, 而是比N大的數(shù)字, 比如N+M, 這樣發(fā)送方接收到確認(rèn)消息時(shí), 就能方便的知道ACK對(duì)應(yīng)的原始請(qǐng)求還是重傳請(qǐng)求.
4. ACK Delay
TCP計(jì)算RTT時(shí)沒(méi)有考慮接收方接受到數(shù)據(jù)發(fā)發(fā)送方確認(rèn)消息之間的延遲, 如下圖所示, 這段延遲即ACK Delay. QUIC考慮了這段延遲, 使得RTT的計(jì)算更加準(zhǔn)確.

5. 更多的ACK塊
ACK, 而QUIC最多可以捎帶256個(gè)ACK block, 在丟包率比較嚴(yán)重的網(wǎng)絡(luò)下, 更多的ACK可以減少重傳量, 提升網(wǎng)絡(luò)效率.瀏覽控制
TCP 會(huì)對(duì)每個(gè)TCP連接進(jìn)行流量控制, 流量控制的意思是讓發(fā)送方不要發(fā)送太快, 要讓接收方來(lái)得及接受, 不然會(huì)導(dǎo)致數(shù)據(jù)溢出而丟失, TCP的流量控制主要通過(guò)滑動(dòng)窗口來(lái)實(shí)現(xiàn)的. 可以看到, 擁塞控制主要是控制發(fā)送方的發(fā)送策略, 但沒(méi)有考慮接收方的接收能力, 流量控制是對(duì)部分能力的不起.
QUIC只需要建立一條連接, 在這條連接上同時(shí)傳輸多條Stream, 好比有一條道路, 量都分別有一個(gè)倉(cāng)庫(kù), 道路中有很多車(chē)輛運(yùn)送物資. QUIC的流量控制有兩個(gè)級(jí)別: 連接級(jí)別(Connection Level)和Stream 級(jí)別(Stream Level).

隨著數(shù)據(jù)不斷被處理, 接收方就有能力處理更多數(shù)據(jù). 當(dāng)滿(mǎn)足(flow control receivce offset - consumed bytes) < (max receive window/2)時(shí), 接收方會(huì)發(fā)送WINDOW_UPDATE frame告訴發(fā)送方你可以再多發(fā)送數(shù)據(jù), 這時(shí)候flow control receive offset就會(huì)偏移, 接收窗口增大, 發(fā)送方可以發(fā)送更多數(shù)據(jù)到接收方.

Stream級(jí)別對(duì)防止接收端接收過(guò)多數(shù)據(jù)作用有限, 更需要借助Connection級(jí)別的流量控制. 理解了Stream流量那么也很好理解Connection的流控. Stream中,
接收窗口=最大接受窗口 - 已接收數(shù)據(jù)而對(duì)于Connection來(lái)說(shuō):接收窗口 = Stream1 接收窗口 + Stream2 接收窗口 + ... + StreamN 接收窗口參考鏈接
HTTP/3 原理實(shí)戰(zhàn)
鏈接:https://mp.weixin.qq.com/s/RX_dMXMfv7NMZMroCz49tA
(版權(quán)歸原作者所有,侵刪)
