The QUIC Transport Protocol


The QUIC Transport Protocol: Design and Internet-Scale Deploymen

0x00 引言

QUIC是Google开发的一个基于UDP的可靠传输协议。由于是Google开发的,又在Google的支持下得到了很多的应用,QUIC还是很有名的。QUIC的几个特点:

  • 避免了TCP繁琐的三次握手操作,加上TLS握手就就更加麻烦了。QUIC改进了连接建立的操作;
  • QUIC的拥塞控制是可拔插的,开始or配置新的拥塞控制算法更加方便;
  • 改进的多路复用;
  • 一开始就为加密传输设计;
  • 支持连接的迁移;

0x01 设计与实现

连接的建立

与TLS连接的建立不同,QUIC能够实现在0RTT建立传输层的连接的同时0RTT建立加密层的连接。如下的所示,一个连接的建立要主要的操作:

  • Initial handshake,初始握手。开始是客户端发送一个 inchoate client hello (CHLO)信息,这个时候服务端会回复一个reject (REJ) 消息。这个reject (REJ) 信息里面包含了不少的信息:

    (i) a server config that includes the server’s long-term Diffie-Hellman public value, 
    (ii) a certificate chain authenticating the server, 
    (iii) a signature of the server config using the private key from the leaf certificate of the chain, and 
    (v) a source-address token: an authenticated-encryption block that contains the client’s publicly visible IP address (as seen at the server) and a timestamp by the server.
    

    这里的source-address token在后面的握手中会用到。客户端收到这个信息之后会回复 complete CHLO消息,这个消息中会包含客户端临时的Diffie-Hellman public value;

  • Final (and repeat) handshake,握手的第二步和之后的握手重复的操作都不需要前面的一步了。都是直接发送一个 complete CHLO消息。而发送这个消息之后就能直接传输数据了。握手成功之后服务端会回复server hello(SHLO)消息,其使用initial keys加密,包含服务端临时的Diffie-Hellman public value。两方得到了对方的Diffie-Hellman public value之后就可以计算出final or forward-secure keys。之后的数据加密使用的是 forward-secure keys;

  • 这里可以看出QUIC使用两个级别的加密方法,一个是开始的客户端的数据使用initial keys,之后的客户端数据和服务端的全部的数据使用forward-secure keys加密。客户端会缓存最初的一步获取到的消息,用于之后的使用。在一些情况下,比如之前缓存的消息过期了,握手操作就会使绊,服务端会返回一个REJ消息。

  • Version Negotiation,版本协议也是在建立连接的时候就执行,避免额外的操作延迟。

quic-establishment

连接

QUIC的连接中相比于TCP的变化,

  • QUIC的连接使用一个64bits的值来确定,这个值是随机生成的。这个也给连接迁移定的特性提供了方便;

  • 另外使用Packet Number代替了TCP的seq,在QUIC中即使包重传了这个值也会变化,而TCP不会变seq;

  • 连接支持多路复用。TCP本身没有这个功能,类似HTTP/2的协议在应用层实现了这个功能;下面的图中有表示流在QUIC的一些结构,流用stream ID标示,

    A QUIC packet is composed of a common header followed by one or more frames, as shown in Figure 5. QUIC stream multiplexing is implemented by encapsulating stream data in one or more stream frames, and a single QUIC packet can carry stream frames from multiple streams.
    

    由于QUIC一开始就考虑到对路复用的设计,QUIC的流之间是不会相互影响的,一个流的包丢了不会影响到其它的。这个解决了HTTP/2依赖于TCP底层实现而导致了一些问题;

  • 验证与加密,QUIC的header与TCP的不同,都是经过了认证or加密的,下面的图中红色的部分是认证过的,而绿色的部分是加密的。

quic-packet

丢失恢复

QUIC也使用类似TCP的ACK的方式来确认收到数据。另外QUIC还在此的基础上做了不少的改进。在ACK的设计中,加上前面的Packet Number的设计,可以使得更加精确地计算RTT,这个对于很多的拥塞控制算法都是很有用的。另外,QUIC支持一次最多传输256个ACK块,

 QUIC’s acknowledgments support up to 256 ACK blocks, making QUIC more resilient to reordering and loss than TCP with SACK . Consequently, QUIC can keep more bytes on the wire in the presence of reordering or loss.

拥塞控制

QUIC的拥塞控制采用了可拔插的设计,而且实现在用户空间,这个给应用新的拥塞控制算法给了很大的方便。另外QUIC的RTT的计算上面也做了改进,考虑到了包处理的时间。QUIC采用的算法并没有和TCP有什么不同。

0x02 其它几点

关于QUIC的另外的几点内容:

  • NAT Rebinding and Connection Migration,连接迁移。得益于使用Connection ID的设计。连接变化的时候,只要保持Connection ID不变即可。连接的迁移变得简单。这个也给类似MPTCP之类的机制方便,而且有了习惯的研究。

  • packet尺寸的考虑;开始的时候QUIC采用的是尽可能更大的数据包,但是后来在事件中发现,太多可能导致丢包的概率增大,

    The rapid increase in unreachability after 1450 bytes is a result of the total packet size— QUIC payload combined with UDP and IP headers—exceeding the 1500 byte Ethernet MTU. Based on this data, we chose 1350 bytes as the default payload size for QUIC. Future work will consider path MTU discovery for QUIC 
    
  • Forward Error Correction。这个是之前的QUIC支持的一个功能,目前的QUIC已经移除了这个。基本的思路就是发送冗余的数据使得在丢失了一部分数据之后能够从已收到的数据中恢复出丢失的数据来。

除了这些,QUIC还有更多的内容。

0x03 评估

这里的详细信息可以参看[1].

参考

  1. The QUIC Transport Protocol: Design and Internet-Scale Deployment, SIGCOMM’ 17.