前言
此系列會(huì)以一系列文章來(lái)介紹Google在傳輸層的新開(kāi)源貢獻(xiàn):QUIC協(xié)議
的一些內(nèi)容儒洛,也是傳說(shuō)中未來(lái)的HTTP3蔚携。
當(dāng)然希太,系列開(kāi)篇肯定要先介紹QUIC是什么,能做什么酝蜒,為什么要用QUIC這些哲學(xué)問(wèn)題誊辉,所以這篇文章不會(huì)涉及一些代碼層面的東西。
QUIC是什么
QUIC(全稱Quick UDP Internet Connections)是谷歌公司制定的一種基于 UDP 協(xié)議的低時(shí)延互聯(lián)網(wǎng)傳輸協(xié)議亡脑,它提供了多項(xiàng)改進(jìn)堕澄,旨在加速HTTP傳輸并使其更加安全邀跃,目標(biāo)是想最終取代TCP和TLS協(xié)議。
可以用一個(gè)公式大致概括如下:
TCP + TLS + HTTP2 = UDP + QUIC + HTTP2’s API蛙紫。
【注意以上都是去別人家摘錄的】
請(qǐng)注意拍屑,QUIC是由Google最早提出并在chromium實(shí)現(xiàn),而現(xiàn)今交給IETF推進(jìn)標(biāo)準(zhǔn)化工作坑傅。所以當(dāng)前QUIC有兩大分支流派丽涩,一種是基于Google的Chromium工程的QUIC實(shí)現(xiàn),也叫做gQUIC裁蚁;另外一種是標(biāo)準(zhǔn)化進(jìn)行中的版本也叫做iQUIC矢渊。
目前兩者由于協(xié)議格式、加密方式等等的不同而不能互通枉证。當(dāng)然從現(xiàn)時(shí)QUIC協(xié)議開(kāi)源庫(kù)支持度矮男、穩(wěn)定性和多平臺(tái)兼容來(lái)看,比較建議采用Google主導(dǎo)的gQUIC室谚,并且gQUIC在后續(xù)也會(huì)打通與iQUIC的兼容毡鉴。
還有一點(diǎn)就是對(duì)于QUIC版本的話,在Google的源碼更新進(jìn)度上面看其版本迭代非常迅速秒赤,所以這里強(qiáng)烈不建議一味求新猪瞬,除非你是大神或者想當(dāng)小白鼠除外,因?yàn)槊恳粋€(gè)版本的升級(jí)導(dǎo)致新版本的協(xié)議格式和API變動(dòng)較大而忙于處理變更入篮。這里建議從一個(gè)穩(wěn)定的版本進(jìn)行入手研究陈瘦,例如業(yè)界廣泛支持的QUIC43/44。
QUIC的優(yōu)勢(shì)
低延遲連接的建立
對(duì)于傳統(tǒng)的HTTPS來(lái)說(shuō)潮售,對(duì)于其傳輸層的TCP握手就需要3個(gè)RTT痊项,如果算上加密部分的話還需要產(chǎn)生額外的RTT,也就是說(shuō)HTTPS進(jìn)行一次完全的握手至少需要4個(gè)以上的RTT酥诽。
然而對(duì)于QUIC來(lái)說(shuō)鞍泉,如果是客戶端首次連接到服務(wù)器,由于QUIC將傳輸與加密結(jié)合在一起的特性所在肮帐,一般來(lái)說(shuō)正常情況下初次握手只需要1個(gè)RTT就可以完成握手咖驮;但是對(duì)于觸發(fā)版本協(xié)商、證書(shū)無(wú)法解密等問(wèn)題當(dāng)然也會(huì)導(dǎo)致多個(gè)RTT的產(chǎn)生训枢。
而重復(fù)連接的情況下握手托修,如果在證書(shū)有效的情況下,客戶端發(fā)送Hello包并不用等待回復(fù)就可以直接發(fā)數(shù)據(jù)加密包肮砾,也就是實(shí)現(xiàn)了傳說(shuō)中的0RTT诀黍。
改進(jìn)的擁塞控制
TCP 的擁塞控制實(shí)際上包含了四個(gè)算法:慢啟動(dòng),擁塞避免仗处,快速重傳眯勾,快速恢復(fù)枣宫。
QUIC協(xié)議當(dāng)前默認(rèn)使用TCP的擁塞控制算法,并在其基礎(chǔ)上進(jìn)行了相應(yīng)的改進(jìn)吃环;當(dāng)然QUIC也支持其他的擁塞控制算法也颤。
主要的改進(jìn)點(diǎn)有:
1、可插拔設(shè)計(jì)
2郁轻、單調(diào)遞增的Packet Number
3翅娶、不允許Reneging
4、更多的Ack塊
5好唯、精確計(jì)算RTT時(shí)間
無(wú)隊(duì)頭阻塞的多路復(fù)用
HTTP2的最大特性就是多路復(fù)用竭沫,而HTTP2最大的問(wèn)題就是隊(duì)頭阻塞。
首先了解下為什么會(huì)出現(xiàn)隊(duì)頭阻塞骑篙。比如HTTP2在一個(gè)TCP連接上同時(shí)發(fā)送3個(gè)Stream蜕提,其中第2個(gè)Stream丟了一個(gè)Packet,TCP為了保證數(shù)據(jù)可靠性靶端,需要發(fā)送端重傳丟失的數(shù)據(jù)包谎势,雖然這時(shí)候第3個(gè)數(shù)據(jù)包已經(jīng)到達(dá)接收端,但被阻塞了杨名,這就是所謂的隊(duì)頭阻塞脏榆。
而QUIC多路復(fù)用可以避免這個(gè)問(wèn)題,因?yàn)镼UIC的丟包台谍、流控都是基于Stream的须喂,所有Stream是相互獨(dú)立的,一條Stream上的丟包典唇,不會(huì)影響其他Stream的數(shù)據(jù)傳輸镊折。
前向糾錯(cuò)
QUIC協(xié)議的每個(gè)數(shù)據(jù)包除了本身的數(shù)據(jù)以外,會(huì)帶有其他數(shù)據(jù)包的部分?jǐn)?shù)據(jù)介衔,在少量丟包的情況下,可以使用其他數(shù)據(jù)包的冗余數(shù)據(jù)完成數(shù)據(jù)組裝而無(wú)需重傳骂因,從而提高數(shù)據(jù)的傳輸速度炎咖。具體實(shí)現(xiàn)類似于RAID5,將N個(gè)包的校驗(yàn)和(異或)建立一個(gè)單獨(dú)的數(shù)據(jù)包發(fā)送寒波,這樣如果在這N個(gè)包中丟了一個(gè)包可以直接恢復(fù)出來(lái)乘盼,除此之外還可以用來(lái)校驗(yàn)包的正確性。
連接遷移
對(duì)于TCP協(xié)議來(lái)說(shuō)俄烁,標(biāo)識(shí)一個(gè)TCP連接需要4個(gè)參數(shù)绸栅,既來(lái)源IP、來(lái)源端口页屠、目的IP和目的端口粹胯。其中的任一參數(shù)改變蓖柔,TCP連接就需要重新創(chuàng)建。這對(duì)于傳統(tǒng)網(wǎng)絡(luò)來(lái)說(shuō)影響不大风纠,因?yàn)閬?lái)源和目的IP相對(duì)固定况鸣。但是在無(wú)線網(wǎng)絡(luò)中,情況就大不相同了竹观。設(shè)備在移動(dòng)過(guò)程中镐捧,可能會(huì)因?yàn)榫W(wǎng)絡(luò)切換(如從WIFI網(wǎng)絡(luò)切換到4G網(wǎng)絡(luò)環(huán)境),導(dǎo)致TCP連接需要重新創(chuàng)建臭增。
QUIC協(xié)議使用了UDP協(xié)議懂酱,不再需要這四元組參數(shù)。同時(shí)QUIC協(xié)議實(shí)現(xiàn)了自己的會(huì)話標(biāo)記方式誊抛,稱為連接UUID列牺。當(dāng)設(shè)備網(wǎng)絡(luò)環(huán)境切換時(shí),連接UUID不會(huì)發(fā)生變化芍锚,因此無(wú)需重新進(jìn)行握手昔园。
PS:基于QUIC相對(duì)于TCP的優(yōu)點(diǎn)的網(wǎng)上文章已經(jīng)爛大街了,其主要是出自Google的文檔翻譯并炮。這里簡(jiǎn)單的進(jìn)行了一些的介紹就過(guò)了默刚,如果還想進(jìn)一步了解的話建議參考其他文章或者Google發(fā)布的QUIC相關(guān)的文檔,但是對(duì)于開(kāi)發(fā)實(shí)戰(zhàn)意義并非是非常重要的逃魄,只要還是源碼為王荤西,暫時(shí)覺(jué)得只是合適吹水 O(∩_∩)O
QUIC相關(guān)開(kāi)源庫(kù)
chromium:quic-client/server-demo模塊
參考地址:https://www.chromium.org/quic
Google提供的一個(gè)QUIC的源碼使用Demo,但是值得注意的其是封裝了支持HTTPS的QUIC實(shí)現(xiàn)伍俘,如果你想在模仿TCP Socket進(jìn)行QUIC傳輸開(kāi)發(fā)的話這個(gè)方案可能不適合你邪锌。
重點(diǎn)敲黑板,這個(gè)Demo主要用于集成測(cè)試癌瘾,其并不具備大規(guī)模的生產(chǎn)環(huán)境使用的性能的可能性觅丰;換句話說(shuō),它就只是一個(gè)玩具妨退,但是這個(gè)玩具挺值得你去玩味妇萄。
PS:后續(xù)會(huì)有一篇該部分的源碼簡(jiǎn)單剖析的文章。
chromium:net模塊
參考地址:https://chromium.googlesource.com/chromium/src.git
如果你想在Android咬荷、iOS冠句、Linux上面更靈活的使用QUIC的話,我覺(jué)得chromium的net模塊是你的最好選擇幸乒。
如果你需要封裝QUIC在HTTP/HTTPS上面使用的話懦底,可以參考上面的 quic-client/server-demo
的源碼的相關(guān)使用方法,其實(shí)也就主要是研究QUIC源碼庫(kù)在spdy部分的內(nèi)容罕扎。
如果你需要封裝QUIC在更底層模仿TCP Socket操作的話聚唐,不妨看看quartc這個(gè)模塊下面的API實(shí)現(xiàn)丐重,具體的參考net下面的 quartc_session_test.cc
這個(gè)文件或者參考github上面的開(kāi)源庫(kù)posix_quic,不過(guò)后者是基于libquic的拱层,API的調(diào)用流程并不一定適合你開(kāi)發(fā)的版本弥臼,但是可以提供大方向的參考。
PS:后續(xù)的文章也大部分是基于這個(gè)模塊展開(kāi)根灯。
quic-go
參考地址:https://github.com/lucas-clemente/quic-go
quic-go是使用Go語(yǔ)言來(lái)重寫(xiě)的QUIC協(xié)議實(shí)現(xiàn)庫(kù)径缅,從github上面看其對(duì)于iQUIC和gQUIC這兩個(gè)分支流派都提供了支持,這個(gè)庫(kù)當(dāng)前也是比較活躍的烙肺。
從測(cè)試結(jié)果來(lái)看其穩(wěn)定性和對(duì)于多端的支持相對(duì)于chromium來(lái)說(shuō)仿佛就是一個(gè)小弟弟纳猪,但其也不能掩蓋這個(gè)就是以前我們爸媽口中別人家的好孩子般存在。當(dāng)然其性能還需要打磨桃笙,對(duì)于大規(guī)模線上應(yīng)用還是需要謹(jǐn)慎考慮氏堤。
libquic
參考地址:https://github.com/devsisters/libquic
libquic已經(jīng)有多年沒(méi)有更新了,其應(yīng)該是民間從chromium中提取QUIC相關(guān)源碼以及其依賴項(xiàng)而形成一個(gè)簡(jiǎn)易的開(kāi)源代碼庫(kù)搏明,對(duì)于苦于需要找個(gè)梯子下載動(dòng)輒數(shù)十個(gè)GB的chromium源碼開(kāi)發(fā)者來(lái)說(shuō)鼠锈,無(wú)疑是一個(gè)福音,這個(gè)庫(kù)很方便我們快速嘗試QUIC的開(kāi)發(fā)星著。
其支持 ninja 和 cmake 兩種編譯方式购笆,但是遺憾的是從反饋上來(lái)看這個(gè)庫(kù)并不支持iOS平臺(tái)的編譯。
基于這個(gè)平臺(tái)的 HTTP 封裝實(shí)現(xiàn)有 goquic 和 TCP Socket 封裝實(shí)現(xiàn)有 posix_quic虚循。
proto-quic
參考地址:https://github.com/google/proto-quic
這個(gè)庫(kù)是Google在chromium上面抽取出來(lái)發(fā)布于github的一個(gè)快速驗(yàn)證QUIC的開(kāi)源庫(kù)同欠,同libquic
一樣并不需要下載太多的源碼,但是其僅僅保證在Ubuntu上是可用的横缔,現(xiàn)在Google已經(jīng)轉(zhuǎn)向了quiche
這個(gè)開(kāi)源分支上面進(jìn)行獨(dú)立QUIC庫(kù)的開(kāi)發(fā)铺遂。
在筆者寫(xiě)這篇文章的時(shí)候,其github上面的代碼已經(jīng)被清空茎刚;不難預(yù)期這個(gè)源碼被整個(gè)刪庫(kù)跑路的日子也不會(huì)太遠(yuǎn)了襟锐。
quiche
參考地址:https://quiche.googlesource.com/quiche
更新速度極快的谷歌QUIC開(kāi)源代碼庫(kù),其主要目的是希望將QUIC從chromium這個(gè)龐大的庫(kù)獨(dú)立出來(lái)作為其上游的實(shí)現(xiàn)方案來(lái)提供QUIC協(xié)議的支持膛锭,但是由于其也只是剛剛開(kāi)始從 https://cs.chromium.org/chromium/src/net/third_party
中遷移過(guò)來(lái)捌斧,目前相關(guān)文檔比較缺乏而且源碼結(jié)構(gòu)變動(dòng)過(guò)大;暫時(shí)并不建議入手研究泉沾,但是強(qiáng)烈建議重點(diǎn)關(guān)注。
chromium:Cronet模塊
參考地址:https://developer.android.com/guide/topics/connectivity/cronet
Cronet主要為chromium的net模塊進(jìn)行了Android/iOS端的封裝妇押,并提供了相應(yīng)的Java和OC接口跷究,所以我們?cè)谝苿?dòng)端也是可以通過(guò)Cronet使用net模塊里面QUIC協(xié)議。如果在客戶端APP想要快速驗(yàn)證使用基于QUIC的HTTP請(qǐng)求的話敲霍,Cronet是一個(gè)非常合適的方案俊马,但是在簡(jiǎn)單使用的前提下其靈活性也相對(duì)較差丁存。
Stellite
參考地址:https://github.com/line/stellite
這個(gè)是利用了Cronet,用C++封裝了一層API而得到的這個(gè)Stellite開(kāi)源庫(kù)柴我,解決了我們希望能在C/C++層面進(jìn)行簡(jiǎn)單快速使用QUIC相關(guān)協(xié)議的需求解寝。當(dāng)然,對(duì)于靈活性和效率肯定沒(méi)有比不上chromium的原生邏輯實(shí)現(xiàn)艘儒。
Caddy
參考地址:https://github.com/mholt/caddy
Caddy是當(dāng)前支持QUIC的一個(gè)比較健壯的Web服務(wù)器聋伦,其底層是基于quic-go的實(shí)現(xiàn)。相對(duì)于nginx等框架還未提供對(duì)quic的支持界睁,實(shí)驗(yàn)性支持quic的caddy也是當(dāng)前web服務(wù)器支持QUIC協(xié)議的唯一理想選擇觉增。
結(jié)語(yǔ)
好了,這篇文章主要目的就是簡(jiǎn)單介紹一下QUIC這個(gè)協(xié)議翻斟,以及可用于研究QUIC的一些開(kāi)源庫(kù)逾礁,接下來(lái)主要會(huì)圍繞chromium庫(kù)來(lái)介紹一下基于QUIC的相關(guān)開(kāi)發(fā)工作。
本文發(fā)布于 簡(jiǎn)書(shū)访惜。
End!