Skip to content

[SIGCOMM’2017] QUIC

内容纲要

Google的习惯就是先自己搞出来玩几年,然后写篇paper,之前的BBR和B4都是这样的套路,QUIC也不例外。

QUIC采用UDP作为传输层协议,即QUIC在应用层实现,这样做的好处是没必要和OS绑在一起更新。QUIC并不使用五元组来标记一条流,而是通过使用流ID标记。

为什么设计QUIC?

Handshake Delay

TCP采用三次握手建立连接,前两次握手是不能传输数据的,第三次握手(ACK包)是可以传输数据的,也就是说最少需要经过一个RTT才能传输数据,但对于一些短流来说,可能它们的数据包传输都不要一个RTT,所以握手开销相对于来说就有点大。

Head-of-line Blocking Delay

先说下HTTP协议在TCP这一块的演变过程,HTTP/1.0支持浏览器为每个域名建立多个连接,实现并发请求,但是连接数目有限制,防止被误认为DoS攻击。还有HTTP/1.0协议规定,服务端每次回完响应包后,会断开连接,下次想继续请求得重新建连接。不断的建立连接会造成带宽浪费和增加延迟。
HTTP/1.1为避免HTTP/1.0每次请求都要创建连接的缺陷,默认开启keep-alive(也就是常说的长连接),同时支持pipelining技术,即在一个TCP连接里,一个HTTP请求发出去后,在收到这个请求的响应前,可以继续传送多个HTTP请求。所有的请求-响应都是按序进行的,即客户端发送多个请求,服务端按请求的顺序依次响应,客户端按发送顺序接收响应,但这形成了所谓的“Head-of-line Balocking”问题。
HTTP/2.0提出了多路复用(Multiplexing)技术解决“Head-of-line Blocking”,即在一个TCP连接内可以同时进行多个HTTP请求,它们的响应没有顺序要求。至于paper中提到需等丢失的TCP segment重传上缴“时间税”问题,个人觉得用来说HTTP/2.0的缺陷有点牵强了,这个是所有使用TCP作为传输协议都会遇到的问题。

QUIC设计和实现

QUIC的设计有以下几个目标,易部署,安全,降低握手和“Head-of-line Blocking”开销。虽然在传输层采用UDP,但QUIC有连接的概念,提供重传、丢失恢复和流控等一系列类似TCP的特性。

连接建立

刚开始客户端没有服务端的信息,所以需要通过握手建立连接,不同于TCP的三次握手,QUIC在尝试进行握手之前,客户端会向服务器发送初始问候(CHLO)消息以引发拒绝(REJ)消息。拒绝消息包含如下信息:
i)服务器配置信息,包括服务端的long-term Diffie-Hellman公共值;
ii)认证服务器的证书链;
iii)使用来自链的叶子证书的私钥对服务器配置进行签名;
iv)asource-address令牌:一个经过身份验证的加密块,其中包含客户端的公开可见IP地址(如在服务器上看到的)和服务器的时间戳。


图1 Timeline of QUIC’s initial 1-RTT handshake, a subsequent successful 0-RTT handshake, and a failed 0-RTT handshake.

客户端在以后的握手中将此令牌发送回服务器,以证明其IP地址的所有权。 客户端收到服务器配置后,它将通过验证证书链和签名来对配置进行增值。 然后,它发送完整的CHLO,其中包含客户的短暂Diffie-Hellman公共值。QUIC只在最开始握手有一个RTT开销,当有了服务器提供的信息后,以后握手都只需0RTT。

流多路复用

为避免TCP的顺序发送导致的“Head-of-line Blocking”问题,QUIC支持在单连接内传输多个流,以确保丢失的UDP数据包仅影响自己的流, 在其他流上接收到的后续数据可以继续进行重组,并传递给应用程序。


图2 QUIC包结构,红色是经过身份验证但未加密的公共头,绿色表示已加密的正文。随着IETF对QUIC的标准化,这种数据包结构也在不断发展

丢包恢复

每个QUIC数据包都携带一个新的数据包编号,包括那些携带重发数据的数据包编号。 这种设计避免了需要使用单独的机制来区分重传的ACK和原始传输的ACK,从而避免了TCP的重传歧义问题。数据包编号表示一个明确的时间顺序,与TCP中的数据包相比,它可以更简单,更准确地检测丢失。
QUIC的确认最多支持256个ACK块,这使QUIC在重新排序和丢失方面比具有SACK的TCP更具弹性。

流控

QUIC的流控分两个级别,流级别流控和连接级别流控。流级别流控,QUIC通过流ID和偏移量告诉对端每条流可以发送的数据量。连接级别流控,QUIC通过限制接收缓冲区的buffer size来限制发送端可以发送的数据,其实也就是对所有流信息的汇总,然后根据buffer size剩余可用大小来通告发送端能发送多少数据。如果只是单纯的采用流级别的流控,当一个连接内有多条流,那么就会存在receive buffer被爆的问题。
另外流与流之间可以乱序,比如流A比流B线传输,但是流A有数据包丢失需要重传,这时流B率先完成传输,那么流B就可以先交付给应用层。QUIC不支持流内乱序交付,比如流A,必须等丢失的包到了后有序交付给应用层。

拥塞控制

QUIC同TCP一样,默认采用Cubic作为拥塞控制算法,同时支持BBR和PCC等拥塞控制算法。就不做过多介绍了。
QUIC引入了前向冗余纠错码,如果接收少量的丢包或错包,可以借助冗余纠错码恢复,降低丢包重传概率。
NAT重新绑定和连接迁移
QUIC的连接通过64位的连接ID标识,也就是说当IP和端口发生改变时,QUIC也能正常运行。此类更改可能是由于NAT超时和重新绑定或客户端将网络连接更改为新的IP地址引起的。

QUIC支持协商

客户端不事先知道给定服务器是否支持QUIC。 当客户端第一次向服务器发出HTTP请求时,它会通过TLS / TCP发送该请求。 服务器通过在HTTP响应中包含“ Alt-Svc”标头来通过支持QUIC。 此标头告诉客户端,可以使用QUIC尝试连接到服务器。
在对同一服务器的后续HTTP请求中,客户端对使用QUIC还是TLS / TCP连接会产生竞争,但通过对TLS / TCP的连接最多延迟300 ms来优先使用QUIC连接。 无论哪种协议成功建立连接,首先都会导致该请求被使用。 如果在路径上阻塞了QUIC,或者QUIC握手数据包大于路径的MTU,则QUIC握手失败,客户端将使用后备TLS / TCP连接。

性能评估

paper定义了三个尺度来对比较QUIC和TLS/TCP的性能,分别是:search latency、video playback latency and video rebuffer rate。


图3 QUIC和TCP在3个不同指标下的比较

参考文献

[1] https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/46403.pdf

+1
Published in论文阅读

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。