QUIC 学习入门概念及资料整理
在学习 QUIC 协议的路上,有很多的博客把 QUIC 的协议讲的很透彻,但是对于一些入门的细节并没有讲的很清楚,导致在学习 QUIC 的时候,存在一定的困难。在这篇文章里,我将补充一些有利于新手理解 QUIC 协议的知识点。
名词解释
RTT
round trip times
,在发送真正的 payload 之前,C/S
双方需要沟通的轮数。例如 TLS 协议需要 2 轮沟通后客户端才能发送 payload,所以 TLS (1.1,1.2)是 2-RTT 协议。
0-RTT 和 1-RTT
0-RTT
表示 Client 在首次与 Server 握手的时候就已经发送了数据流,1-RTT
表示 Client 需要与 Server 进行一来一回的握手通讯之后,才能发送数据流。
一般来说在不启用 0-RTT 特性的时候,都是按 1-RTT 进行通讯的,并且首次握手都是 1-RTT,只有 Client 缓存了 Token 之后,才能够启用 0-RTT,在首包中进行传输。
TCP 消耗 1.5RTT
如图所示,三次握手过程为 1.5RTT,完整的一来一回表示一个 RTT,第三次握手并没有返回过程。
TLS1.3
TLS1.3 在首次握手时,需要消耗一个 RTT 建立连接,服务器会发送一个 NST(New-Session-Ticket)的报文给客户端,该报文中记录 PSK 的值、名字和有效期等信息,双方下一次建立连接时,可以使用该 PSK 值作为初始密钥材料。
当连接断开重连时,TLS1.3 客户端缓存的 PSK 可以直接作为认证信息,在握手的时候直接对 Application Data 进行加密传输,存储在握手报文的 Early Data 中,实现 0-RTT 的效果。
包空间,包号和帧
包空间为:Initial
包号为:PacketNumber: 0
帧为:AckFrame
ACK 帧, CryptoFrame
加密帧
单独的包号空间
QUIC 为每个加密级别使用单独的包号空间,除了 0-RTT 和所有代的 1-RTT 密钥使用相同的包号空间。单独的包号空间确保一个加密级别上发送的包的确认不会导致不同加密级别上发送的包的虚假重传。拥塞控制和往返时间 (RTT) 测量是跨包号空间统一的。
单调递增的包号
TCP 将发送端的传输顺序与接收端的交付顺序合并在一起,这会导致携带相同序列号的相同数据的重传,从而导致 “重传歧义”。QUIC 将两者分开:QUIC 使用包号来指示传输顺序,并且所有的应用程序数据都在一个或多个流中发送,交付顺序由 STREAM 帧中编码的流偏移确定。
QUIC 的包号在包号空间内严格递增,并直接编码传输顺序。较高的包号表示该数据包是较晚发送的,而较低的包号表示该数据包发送的较早。当检测到包含 ACK 诱发帧的包丢失时,QUIC 会将必要的帧重新打包进具有新包号的新数据包中,则当收到 ACK 时,这种做法可以消除该 ACK 在确认哪个数据包的歧义性。因此,可以进行更精确的 RTT 测量,很容易检查到虚假重传,并且可以仅仅基于包号来统一应用诸如快速重传这样的机制。
这个设计点大大简化了 QUIC 的丢失检测机制。大多数 TCP 机制都会隐式地尝试根据 TCP 序列号推断传输顺序 - 这是一项比较艰难的任务,特别是当 TCP 时间戳不可用时。
帧
一个 quic 包中可以包含多个帧,不同类型的消息,对应不同的帧,例如 ACKFrame,StreamFrame,DatagramFrame.
ALPN
RFC 7301 : Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension
允许客户端在连接建立期间提供多个应用协议。客户端包含的传输参数对客户端提供的所有应用协议生效。应用协议可以指定传输参数值,例如初始流控上限。然而,应用协议对传输参数值设置限制,可能导致因为限制冲突使得客户端不能提供多种应用协议支持。
通讯方式
知道了 QUIC 的优缺点,以及协议细节之后,具体 QUIC 到底怎么通讯的,如何保证可靠性呢?目前 QUIC 的具体通讯实现有两种方式:
Stream 流
QUIC Stream 数据流是 QUIC 主要数据传输的载体,可靠传输是其需要保证的基本功能。也是 QUIC 最早支持实现的通讯方式,用来提供一种有序可靠的数据传输方式,大多数的 QUIC 通讯都是基于这种方式进行通讯。
Datagram
同一 QUIC 连接里面可以同时包含可靠 Stream 传输和不可靠数据传输,它们可以共享一次握手信息,分别可以作用于 TLS 和 DTLS,可降低握手延迟。
QUIC 在握手上比 DTLS 更加精准,它对每个握手数据包加上了超时重传定时器,能够快速感知握手包的丢失和恢复。
QUIC Datagram 的不可靠传输也可以被 ACK,这是一个选项,如果有 ACK,可以让应用程序感知到 QUIC Datagram 的成功接收。
QUIC Datagram 也适用于 QUIC 的 CC。
这些特性能够让实时音视频流、在线游戏和实时网络服务等应用的传输得到极大的效率提升。
官方资料对于Datagram
的描述,与 Stream 的最大区别在于,Datagram
是不可靠的数据传输,适用于实时音视频流、在线游戏和实时网络服务等业务,应该是这类业务可以牺牲数据的可靠性,以提升数据的传输效率。相对来说 Stream 为了维护数据的可靠性传输,增加了缓存等机制,存在性能损耗,对吞吐量也有一定的影响,如果业务确实不关注严格的可靠性,允许部分数据丢失,比如可能视频播放中掉帧,只要不严重,那么对于效率的提升就是可以接受的。
推荐的学习资料
大神翻译的中文QUIC协议文档: 可以说是非常全面的 QUIC 知识手册,可以在这里找到你想找到的几乎所有的 QUIC 协议细节。
QUIC 0-RTT实现简析及一种分布式的0-RTT实现方案: 把 QUIC 的协议通讯过程讲的很清楚
跟坚哥学QUIC系列:加密和传输握手: yomo 开源项目的贡献者,yomo 是一个基于 quic 实现的流式通讯框架
一些开源项目
quic-go : Golang 实现的比较成熟的 QUIC 实现。
yomo : 一个流式通讯框架,这家公司还做了一个公有云服务,用来解决长距离,低延时的通讯传输问题。
xquic:是一个遵循 IETF 标准的 QUIC 和 HTTP/3 的客户端和服务端实现, 阿里开源的,但是目前主要是阿里自己的手淘业务在用,还在积极开发中。
版权声明: 本文为 InfoQ 作者【黄继承】的原创文章。
原文链接:【http://xie.infoq.cn/article/28c78492f3548db589d60c748】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论