聊聊QUIC


一、QUIC是什么?

        QUIC是快速UDP网络连接(Quick UDP Internet Connections)的缩写,  是Google公司研发的一种基于  UDP  协议的低时延互联网传输协议。在过去,QUIC用在HTTP上,后来IETF(国际互联网工程任务组)发现QUIC是个好东西,于是希望把QUIC从HTTP中分离出来(如 : IP / UDP / QUIC / HTTP)。在2016年IETF会议中,HTTP-over-QUIC协议被重命名为HTTP/3,并成为  HTTP  协议的第三个正式版本。

        社区中的人们已经使用非正式名称如iQUIC和gQUIC来指代这些不同版本的协议,以将QUIC协议与IETF和Google分开,在wireshark中可以通过输入gquic或quic过滤quic报文。

QUIC是个很大的协议,位于传输层,使用TLS 1.3(RFC 8446),在UDP之上实现类似于TCP + TLS + HTTP/2。

QUIC位于传输层


QUIC相关时间:

2013 年由Google提出

2015 年被提议作为 IETF 的标准草案

2016年11月IETF召开了第一次QUIC工作组会议

二、为什么是UDP,而不是TCP?

吐槽历代HTTP

1、HTTP0.9 只有Get方法

2、HTTP1.0 使用短连接,每次请求都要经过三次握手,四次挥手。需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。

3、HTTP 1.1 队头阻塞。

4、HTTP2.0  IETF借鉴了SPDY,虽然消除了以请求为单元的队头阻塞,但是请求内是以TCP同步发送,没能根治队头阻塞。

对比各个版本的HTTP


2、吐槽TCP:

        a. TCP由操作系统内核实现,如果要改变,那么所有操作系统都得改变,不现实。

        b. TCP对报文控制太精细,很难有改进的空间,数据包经过严格控制,不能来一场说走就走的旅行。曾经Google有人提出TFO (tcp fast open)对TCP扩展,也提交了RFC,但是没普及。

        c. UDP报文结构简单,在此基础上做文章很方便。而且QUIC并非基于系统内核修改,可以进行快速迭代更新。

3、吐槽完:

UDP是不可靠传输,IP也是不可靠传输。为啥QUIC不直接建立在IP上呢?

世界上有很多终端设备通过NAT通信,所有的NAT产品都支持TCP/UDP,根据IP+PORT与终端的会话一一对应。如果QUIC建立在IP之上,并没有端口号,意味着每一个NAT设备只能记忆一个终端的会话,一个全球IP 与一个私有IP的一一映射。那将意味着NAT设备后只能有一个会话可以访问同一个服务器的页面。那还不如赶紧普及IPv6。

再退一步,即使在IP层之上给到QUIC端口号,那也得所有的NAT设备都得修改可以兼容QUIC的规则。所以QUIC建立在UDP上是唯一出路。

4、QUIC相比现在广泛应用的TCP + TLS + HTTP/2协议有如下优势:

(1)通过减少往返次数,以缩短连接建立时间

HTTPS 及 QUIC 建连过程  


(2)多路复用,解决HTTP/2队头阻塞问题

        QUIC 最基本的传输单元是 Packet,不会超过 MTU 的大小,整个加密和认证过程都是基于 Packet 的,不会跨越多个 Packet。这样就能避免 TLS 协议存在的队头阻塞。Stream 之间相互独立,比如 Stream2 丢了一个 Pakcet,不会影响 Stream3 和 Stream4。不存在 TCP 队头阻塞。

        QUIC  的流量控制类似  HTTP2,即在  Connection  和  Stream  级别提供了两种流量控制。为什么需要两类流量控制呢?主要是因为  QUIC  支持多路复用。Stream  可以认为就是一条  HTTP  请求。Connection  可以类比一条  TCP  连接。多路复用意味着在一条  Connetion  上会同时存在多条  Stream。既需要对单个  Stream  进行控制,又需要针对所有  Stream  进行总体控制。相当于rabbitmq的channel和Connection的关系。

        简单来说,http2解决http1.1在应用层中队头阻塞的问题,但是没有解决传输层TCP的单个报文的重传阻塞(传输层的队头阻塞没有解决)。而UDP没有报文阻塞这个问题,所以基于UDP的quic协议,可以更深一层的解决阻塞问题。

QUIC 多路复用时没有队头阻塞的问题


(3)使用FEC(前向纠错)恢复丢失的包,以减少超时重传

        前向纠错是一种差错控制方式,它是指信号在被送入传输信道之前预先按一定的算法进行编码处理,加入带有信号本身特征的冗码,在接收端按照相应算法对接收到的信号进行解码,从而找出在传输过程中产生的错误码并将其纠正的技术。QUIC用的是一阶冗余,如果有一个Group内有其中一条QUIC报文出错可以修正。如果有超过一个QUIC报文出错,则NACK。

(4)使用一个随机数(CID)标志一个连接,取代传统IP + PORT的方式,使得切换网络环境如从4G到wifi仍然能使用之前的连接。

        当使用手机在 WIFI 和 4G 移动网络切换时,客户端的 IP 肯定会发生变化,需要重新建立和服务端的 TCP 连接。而任何一条 QUIC 连接不再以 IP 及端口四元组标识,而是以一个 64 位的随机数作为 ID 来标识( 由于这个 ID 是客户端随机产生的,并且长度有 64 位,所以冲突概率非常低),这样就算 IP 或者端口发生变化时,只要 ID 不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。

三、QUIC报文

参考 https://tools.ietf.org/html/draft-tsvwg-quic-protocol-02#ref-3

红色为QUIC公共报文头


第一字节为:Public  Flags:

Public Flag的8位如下所示,左边为高位,右边为低位

public flags

如果Bit0被置上(0x01 = PUBLIC_FLAG_VERSION = 0x01),该字段的含义取决于报文是客户端还是服务端发送。如果是客户端发送,这一位被置上表示QUIC Version字段不为空,且QUIC Version字段被填充为客户端的QUIC版本信息。在客户端收到服务端同意建立该版本的连接报文抵达之前,客户端发送的所有报文的这一位必须都要被设置。如果服务端同意建立该版本的连接,那么这一位不用设置。如果这一位被服务端置上,那么表示该报文是版本协商报文(Version Negotiation Packet)。

如果Bit1被置上(0x02 = PUBLIC_FLAG_RESET),表明该报文是公共重置报文(Public Reset packet)

Bit2、Bit3两位表示报文中的Connection ID的长度。直至协商另外一个值之前,在所有的报文中,这两位必须设置被设置为相同(客户端可能请求更少的数据,所以ConnectID的长度需要变化)

0x0C(Bit3及Bit2均为1)表示Connection ID长度是8字节

0x08(Bit3位1,Bit2为0)表示Connection ID长度是4字节

0x04(Bit3位0,Bit2为1)表示Connection ID长度是1字节

0x00(Bit3及Bit2均为0)表示无Connection ID

Bit4、Bit5两位表示每个数据包中存在的数据包编号的字节数。对于帧数据,这两位才使用,对于Public Reset报文及Version Negotiation报文,这两位必须为0

0x30(Bit5及Bit4均为1)表示:包序号是6个字节

0x20(Bit5为1,Bit4为0)表示:包序号是4个字节

0x10(Bit5为0,Bit4为1)表示:包序号是2个字节

0x00(Bit5及Bit4均为0)表示:包序号是1个字节

Bit6:预留给多路径使用

Bit7:未使用,必须为0

Connection ID:客户端随机选择的最大长度为64位的无符号整数。但是,长度可以协商。

QUIC Version:QUIC协议的版本号,32位的可选字段。如果Public Flag & FLAG_VERSION != 0,这个字段必填。客户端设置Public Flag中的Bit0为1,并且填写期望的版本号。如果客户端期望的版本号服务端不支持,服务端设置Public Flag中的Bit0为1,并且在该字段中列出服务端支持的协议版本(0或者多个),并且该字段后不能有任何报文。

Packet Number:长度取决于Public Flag中Bit4及Bit5两位的值,最大长度6字节。发送端在每个普通报文中设置Packet Number。发送端发送的第一个包的序列号是1,随后的数据包中的序列号的都大于前一个包中的序列号。

QUIC报文分为:

1、特殊报文

版本协商报文(Version Negotiation Packets)

只由服务端发送。版本协议报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_VERSION且标识Connection ID长度为8字节,最后面就是服务端支持的协议版本(4字节)。

版本协商报文


公共重置报文(Public Reset Packets)

Public Reset报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_RESET且标识Connection ID长度为8字节,剩余的部分是QUIC Tag。

公共重置报文


2、普通报文

普通的报文被验证(authenticated)且被加密。公有头被验证但是没有加密,从Private Flags字段开始的报文被加密。普通的报文包含AEAD(authenticated encryption and associated data)报文。普通报文必须被解密,并且密文被解密后,明文以Private Header开始。

普通报文中私有头格式


帧报文

除了私有头外,帧包有一系列的基于类型的帧数据的负载,通用的帧包的格式

帧报文

FEC(Forward Error Correction)报文

FEC包(FLAG_FEC标志被置为1)的负载只包含位于FEC组中的每个数据包的空填充负载的XOR值。每个FEC包的FLAG_FEC_GROUP标志也必须被置为1

FEC包


四、浏览器中查看QUIC

有豆瓣,google,Facebook,YouTube,QQ空间。以下是F12豆瓣网的,可以发现豆瓣有在用HTTP1.1,HTTP2.0(h2),QUIC。

在Google新版的Chrome浏览器中,支持QUIC协议,在Chrome浏览器中打开“实验性功能”页面(chrome://flags/),把Experimental QUIC protocol设置enabled。

豆瓣使用QUIC


服务器返回可用的QUIC版本


五、抓包验证

抓不到正常通信的包。将就看个版本匹配失败的例子  - -

客户端发送一个CHLO报文,报文里Public Flags的bit0(Version)设置1,而且设置Version值Q039。创建CID连接号。

客户端发送hello报文


服务端收到客户端的连接请求,返回协商报文,Public Flags的bit0(Version)设置1,并返回可支持的QUIC Version版本列表。

服务端应答可用version


客户端发现服务端返回的版本列表里,并没有符合的,于是发送CONNECTION_CLOSE消息,关闭通信。虽然看到连接关闭的字样,但实际上我是可以访问到豆瓣的,因为此时TCP会有替补,走基于TCP的HTTP通信。

客户端应答版本不一致并关闭


六、支持QUIC的开源项目

Caddy:Go 写的 Web 服务器 ,QUIC只是附属功能,但用它的人更多是用来做QUIC实验 :D, 勉强能用在生产环境。

quic-go :是完全用 go 写的 QUIC 协议栈,开发很活跃,已在 Caddy 中使用,MIT 许可。

Chromium :Google 官方维护基本没有坑,随时可以跟随 chrome 更新到最新版本。不过编译 Chromium 比较麻烦。

七、附录:

1、header压缩

        在HTTP1.x中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500~800字节的负荷。

        HTTP2.0使用HPACK算法来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。

2、参考文档 https://tools.ietf.org/html/draft-ietf-quic-http-17

3、FEC算法  https://blog.csdn.net/u010178611/article/details/82656838 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 科普:QUIC 协议原理分析 作者介绍:lancelot,腾讯资深研发工程师。目前主要负责腾讯 stgw(腾讯安全...
    吸霾少年阅读 9,759评论 0 19
  • 茫茫人海两相遇,初相知,共相望。纵使争吵泪不断。 携手相伴共风雨,爱之深,恨之切,只因我们最相顾。
    我很简单一介俗人阅读 164评论 1 3
  • 风吹起我的发 丝丝缕缕将岁月结扣相加 发丝飘过曾经的期待 又在天空中扬起幻想的沙 偷偷织就一城缥缈的线 在错中复杂...
    我是深海精灵阅读 330评论 0 0
  • 晚饭后散步,走得有点远。回去的时候,一想到还要走三、四十分钟的路程回去,腿就软了起来。无奈,不争气地掏出手机,...
    Banagher阅读 240评论 0 0
  • 一群有梦想的青年,最后一个晚上,在KTV,激情慷慨,唱浮夸,死了都要爱,灯红酒绿的包厢里,有烟味,有酒气,有美...
    藕吟诗语阅读 446评论 0 2