声明#
本文可以自由转载但需注明原始链接。本文为本人原创,作者LightningStar,原文发表在博客园。本文主体内容参考论文[1]完成。
介绍#
QUIC,发音同quick,是"Quick UDP Internet Connections"的简称,是一种通用的传输层网络协议。QUIC与TCP相同,是一种有连接的传输协议。但是与TCP不同的是QUIC是建立在UDP传输层协议之上的,实现了在两个端点之间的多路复用。QUIC的是在用户空间实现的,TCP/UDP则是在内核空间实现的。[2]
QUIC所处的网络层次如下图所示。图源文献[1:1]。
优势#
Quic 相比现在广泛应用的 http2+tcp+tls 协议有如下优势:
1、减少了 TCP 三次握手及 TLS 握手时间。
2、改进的拥塞控制。
3、避免队头阻塞的多路复用。
4、连接迁移。
5、前向安全。
建立连接(握手)#
QUIC实现了快速握手,并把握手过程分为两种情况,分别是1-RTT和0-RTT。在介绍这两种握手过程之前,读者需自行熟悉Diffie-Hellman算法的基本原理[3]。
在上图(文献[1:2])中显示了三种不同情况的连接过程。其中最左边的图表示的是第一次连接时的情况,中间的图表示重复连接的情况(在一定条件下,客户端可以重新连接服务器而不需要从初始化情况连接),最右边的图则是重连失败之后从初始话连接的情况。最后一种情况是第一种情况的组会,0-RTT也是1-RTT的一部分,后文中将重点介绍1-RTT的连接过程。
1-RTT#
第一次握手:
- 客户端主动向服务器发送Inchoate CHLO报文
- 服务器会向客户端发送REJ报文。REJ报文包含了服务器的配置信息,如长期的Diffie-Hellman值,服务器配置的签名,source-address-token(stk, 用于验证的加密块,包含有服务器看到的客户端的IP地址和服务器当前的时间戳,之后客户端会将该stk发回)等,为了进行身份证明还会使用私钥进行签名,同时也可以防篡改;
- 在收到服务器的配置信息后,客户端会通过证书链机制验签,并实现对服务器的身份认证。
第二次握手:
- 客户端在通过对服务器的验证之后,客户端会生成一个Diffie-Hellman值。此时客户端有了自身和对方的Diffie-Hellman值,就可以计算出初始密钥(initial key, ik);
- 客户端将包含有DH公开之的明文Complete CHLO发送至服务器;
- 客户端使用ik对请求数据加密,发送至服务器;
- 服务器收到Complete CHLO之后就可以获得客户端的Diffie-Hellman的值,就可以计算出初始密钥。
- 服务器立即向客户端发送SHLO报文(ik加密的)。SHLO报文含有一个服务器临时Diffie-Hellman值,可以用于计算前向安全的密钥(会话密钥);
- 服务器收到加密的请求数据,使用初始密钥进行解密;
- 服务器使用会话密钥对响应数据进行加密,发回给客户端。
- 客户端在收到SHLO之后使用初始密钥解密得到服务器的临时DH公开值,根据该临时值计算出会话密钥;
- 客户端收到加密的响应数据后,使用会话密钥进行解密。
整个握手过程会在2个RTT内完成。
0-RTT#
客户端在重连同一个服务器时,会使用已经缓存的服务器相关配置信息(stk,DH公开值等信息),并直接向服务器发送Complete CHLO报文,并使用ik对请求报文进行加密。但是服务器方面会标识相应的stk等信息已经过期,这时服务器会发送REJ信息,客户端需要重新与服务器进行连接。
如果没有过期的话,就可以直接建立连接,省下了重新建立连接的开销。
前向安全性#
所谓前向安全性就是指,在最后一次握手时,会生成一个会话密钥sk。这样即使服务器的长期DH值被破获,且生成了初始密钥ik,也无法对会话中的数据进行解密。
多路复用机制#
基于TCP的应用程序会在TCP单字节流抽象层中实现多路复用。为了避免由于TCP顺序传递导致的头部阻塞(head-of-line blocking)[4],QUIC支持在单个UDP连接中复用多个流,并保证UDP报文的丢失仅影响相应的流,而不会影响其他的流(stream)。
可以在QUIC流上构建任意大小的应用程序报文,最多支持的字节。并且stream的实现是轻量级的,即使消息报文很小也可以为它们使用单独的流。每一个Stream都有stream ID唯一标识。这些流ID由客户端/服务器进行静态分配。客户端主动发起的流的ID永远是奇数,服务器发起的流的ID是偶数。这样可以避免冲突。当在一个未使用过的流上发送数据时,流会自动创建;当需要关闭时,就会在最后一帧数据上设置一个FIN的标志指示接收方关闭流。如果发送方或接收方确定不再需要流上的数据,则可以取消流,而无需断开整个 QUIC 连接。尽管流是可靠的抽象,但 QUIC 不会为已取消的流重新传输数据。
一个QUIC包是由一个公共的头后面跟着一个或多个帧组成的,如下图(图源[1:3])所示。QUIC流复用是通过将流数据封装在一个或多个流帧中来实现的,单个QUIC包可以携带来自多个流的流帧.
报文丢失重传#
TCP 序列号有助于提高可靠性,并表示在接收方传送字节的顺序。这种混淆会导致“重传模糊”(retransmission ambiguity)问题,因为重传的 TCP 段携带与原始数据包相同的序列号 。 TCP ACK 的接收者无法确定 ACK 是为原始传输还是为重传而发送,并且通常通过昂贵的超时来检测重传段的丢失。每个 QUIC 数据包都携带一个新的数据包编号,包括那些携带重传数据的数据包。这种设计不需要单独的机制来区分重传的 ACK 和原始传输的 ACK,从而避免了 TCP 的重传模糊问题。流帧中的流偏移用于传递排序,数据包编号表示一个明确的时间顺序,这使得丢失检测比 TCP 更简单、更准确。
QUIC的ACK显示地记录了接收的数据报文和ACK之间的延迟。单调增加的报文编号一起,可以精确估算RTT,有助于丢失检测。QUIC的确认报文支持多达256个ACK,这是使得QUIC比带有SACK的TCP更能适应重新排序或丢失的情况下在线路上保留更多字节。
更多内容参见[5]。
流量控制(Flow Control)#
当应用程序从QUIC的接收缓冲区中读取数据较慢时,留恋控制就会限制接收者必须保持的接收缓冲区大小。一个缓慢耗尽的stream会逐渐耗尽整个连接connection的缓冲区,因此必须要限制QUIC连接上的每个流可以消耗的缓冲区大小,避免消耗其他流的缓冲区的大小。这样可以改善流之间潜在的队头阻塞(head-of-line blocking)。因此QUIC采用连接级别的流量控制(connection-level flow control),这样可以限制发送者在所有流中接收者使用的聚合缓冲区;采用流级别的流量控制(stream-level flow control)可以限制发送者在任何给定流上使用的缓冲区。
与HTTP/2类似,QUIC采用基于信用的流量控制。QUIC接收器在每个流中通告接收器愿意接收数据的绝对字节偏移量。在特定流上发送、接收和传递数据时,接收器会定期发送窗口更新帧,以增加该流的窗口偏移限制,从而允许对等方在该流上发送更多数据。连接级流量控制的工作方式与流级流量控制相同,但传递的字节数和接收到的最高偏移量是所有流的。
拥塞控制(Congestion Control)#
QUIC支持的拥塞控制算法有:
Reno(TCP用的)、基于Pacing的拥塞控制算法(PBCCA)、TCP CUBIC等。
连接迁移#
QUIC连接使用随机生成的64bit的cid唯一确定。cid允许客户机在网络之间漫游,而不受网络或传输层参数变化的影响。
cid使得客户端能够独立于网络地址转换(network address translation, NAT)之外。cid 在路由中起着重要作用,特别是用于连接标识的目的。此外,使用 cids 可以通过探测连接的新路径实现多路径。
在连接迁移期间,端点假设对等方愿意在其当前地址接受数据包。因此,端点可以迁移到新的 IP 地址,而无需首先验证对等方的 IP 地址。新的路由路径可能不支持端点的当前发送速率。在这种情况下,端点需要重新构建它的拥塞控制器。另一方面,从一个新的对等地址接收非探测包 ,确认对等地址已迁移到新的 IP 地址。
实现参考#
- Google Quic Project[6]
拓展阅读#
-
Implementation and analysis of QUIC for MQTT[7]
-
RFC 9000 QUIC: A UDP-Based Multiplexed and Secure Transport
QUIC的初步标准定义。
参考文献#
LANGLEY A, RIDDOCH A, WILK A, 等. The QUIC Transport Protocol: Design and Internet-Scale Deployment[C/OL]//Proceedings of the Conference of the ACM Special Interest Group on Data Communication. Los Angeles CA USA: ACM, 2017: 183-196[2022-03-05]. https://dl.acm.org/doi/10.1145/3098822.3098842. DOI:10.1145/3098822.3098842. ↩︎ ↩︎ ↩︎ ↩︎
J. Iyengar and I. Swett. 2016. QUIC Loss Detection and Congestion Control.IETF Internet Draft, draft-ietf-quic-recovery ↩︎
KUMAR P, DEZFOULI B. Implementation and analysis of QUIC for MQTT[J/OL]. Computer Networks, 2019, 150: 28-45. DOI:10.1016/j.comnet.2018.12.012. ↩︎