村通网之也谈 QUIC
注意:由于本人过菜所以本文不会深度剖析 QUIC 协议
什么是QUIC?
QUIC全称 Quick UDP Internet Connection。你可以看到第一个单词是 Quick,快,这不是吹的,它快的原因一部分来自第二个单词 UDP,稍后我们会具体讲到为什么。
为什么选择UDP
以前的 HTTP 不管那个版本都基于 TCP 传输,那么为什么要选择 UDP呢?
众所周知 TCP 连接需要三次握手完成而且 TCP 采取重传机制。 TCP 有一个等待时间,一旦超时便重新传输该数据段,这会造成一定的阻塞,和速度上的一定影响。
而UDP是无连接的而且也不提供可靠性保证,它的可靠性保证由应用层来完成,所以速度更快传输效率更高。当然,QUIC 是提供可靠性保证的,这个也会在下面讲到。
TCP 是由内核实现的,所以 TCP的迭代是非常缓慢的,例如说 TCP Fast Open,仍有大量的系统内核版本不支持它。BBR更是如此,经常需要用户通过编译内核实现。
优势
0RTT建立连接
一般情况下建立一个 HTTPS 需要三个 RTT。而QUIC使用前向安全实现了0RTT数据发送,可谓吊打 TLS 1.2。
等待时延
这里类似 TCP Fast Open,之前已经建立过连接的情况下无需握手,直接传输数据,连接时延为0。
前向冗余纠错
前面有说过 TCP 的重传,这里不再重复。QUIC 采用了前向冗余纠错的方案,将多个包的校验和单独发送一个数据包传输,当数据包丢失时能够通过冗余数据恢复,不需要重传。
多路复用
QUIC 的多路复用和 HTTP/2 类似,在一个 QUIC 连接上可以发送多个请求 (stream),但是 QUIC 的多个 stream 之间没有依赖,这样能极大地缓解队头阻塞。
而 HTTP/2 中任何一个 stream 丢失了一个 TCP Segment,TCP为了保证数据可靠性会重发该 stream,后面的 stream 虽然已经到达接收端,但却被阻塞住了。而且 HTTP2 有 TLS 协议的队头阻塞。
QUIC的基本传输单元为 Packet,不会超过 MTU,且加密和认证都在一个 Packet上,避免了 TLS 的队头阻塞。
拥塞控制
QUIC 使用并改进了 TCP 的拥塞控制,下面我将介绍一下改进的方面:
可拔插
前面说过 UDP 通过应用层来实现,所以不用停机,轻轻 reload 一下便可以轻松修改拥塞控制。
递增的Packet Number
在 TCP 中,重传的 Segment 的 Segment Number 和原来的 Segment 的 Segment Number 一致,那么当客户端接收到 Ack 时就不能判断这是哪个 Segment。当重传 Segment 返回数据时,会导致 RTT 过大;原 Segment 返回数据时又导致 RTT过 小。
QUIC 则不然,重传时 Packet Number 会递增,这就很容易判断是哪个 Packet,这样能使 RTT 的计算十分精确。
但是问题来了,这样怎么保证数据的顺序了?这时 QUIC 引入了一个 Stream Offset 的概念,就算这个包重传它的 Offset 是不会变的,这样子便可以保证了顺序。
再见 Reneging
什么是佩奇 Reneging?就算接收端丢弃已经接收并且上报 SACK 选项的内容,这会给重传带来很大的干扰,因为 SACK 表面收到但是接收端却丢弃了该数据。
QUIC直接禁止了 Reneging,只要 Packet 被返回 Ack 就代表接收端已经收到了它,减少干扰。
打个比方,A 上课给 B 传小纸条,B 收到了之后看都没看就扔了,却告诉 A 已经收到了,所以 A 就会认为 B 已经收到消息。
更多Ack块
TCP 头部仅仅留给了 SACK选项 30 个字节,最大只能提供三个 Block,而 QUIC Ack Frame 却可以提供 256 个 Ack Block。在丢包率比较高的情况下,更多的 Sack Block 可以减少重传量。
Ack Delay
TCP的 Timestamp 只是发送 Ack 的时间,却没有计算从接到 Segment 到发送 Ack 的时间,这个时间叫做 Ack Delay。这会导致 RTT 计算的误差。
比方说寄快递,寄件的时间为 time1,中间快递时间为 time2 (只是比喻,没这么长啦),接收快递时间为 time3。假设接到快递,你知道time1和time3,你就会认为寄件和收件要这么长时间,然而事实上中间还有快递的时间 (导致 RTT 偏大)。 但是要是把快递的时间 time2 标上,这样你就知道这个过程实际上需要的时间 (RTT 更加精确)。
流量控制
QUIC 和 HTTP/2 的流量控制类似,即在 Connection 和 Stream 级别提供了两种流量控制,这也是为了实现多路复用。
通过 window_update 告诉对端自己可以接收的字节数,通过 BlockFrame 告诉对端流量被阻塞。
但是,TCP中windows 向右滑动的长度取决于确认的字节数,如果丢包,windows 便不能超过这个序号。
QUIC 就算丢包,它的滑动也只取决于收到的最大的偏移字节数。
加密报文
TCP 的头部是不经过加密认证的,然而 QUIC 除了少数报文,从 Headers 到 Body都是加密的,更加安全。
连接迁移
TCP 连接由四个元标识,分别为源 IP 源端口 目标 IP 目标端口,一旦一个发生变化这条 TCP 连接就会断。
比方说 NAT 中,DHCP 服务器给你分了个新的 IP,或者是其他客户端抢占端口,这都会使得需要重新建立 TCP 连接。
QUIC使用一个64位的随机数字作为 ID,ID 不变连接就不会中断,而且出现冲突的概率很低。
参考文章
如何看待谷歌 Google 打算用 QUIC 协议替代 TCP/UDP? - Trotyl Yu的回答 - 知乎
科普:QUIC协议原理分析 - 知乎
本文使用 CC BY-NC-SA 4.0 授权
本文链接:https://blog.akinokae.de/archives/polular-science-quic/