浅谈QUIC/http3协议原理与性能分析及部署方案
Author:[email protected] Date:
之前写过《http1.0 与 http1.1的区别》 与 《再谈HTTP2性能提升之背后原理—HTTP2历史解剖》,QUIC协议,现在nginx官方也即将支持。所以还是得跟上时代脚步。
QUIC简史
QUIC(Quick UDP Internet Connection)是谷歌推出的一套基于UDP的传输协议,它实现了TCP + HTTPS + HTTP/2的功能,目的是保证可靠性的同时降低网络延迟。因为UDP是一个简单传输协议,基于UDP可以摆脱TCP传输确认、重传慢启动等因素,建立安全连接只需要一的个往返时间,它还实现了HTTP/2多路复用、头部压缩等功能。
为什么要使用QUIC
众所周知UDP比TCP传输速度快,TCP是可靠协议,但是代价就是 双方确认数据而衍生的一系列消耗,可以参看《再深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP》。其次TCP是系统内核实现的,如果升级TCP协议,就得让用户升级系统,这个的门槛比较高,而QUIC在UPD基础上由客户端自由发挥,只要有服务器能对接就可以。
这些不止让传输速度更快,多路复用等优势,还可应付移动网络里面频发的切换。这些都是quic的优势。
QUIC优势
连接建立延时低
0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。那什么是 0RTT 建连呢?
就是只需要一次往返就能建立HTTPS连接
回顾一下 tcp二次握手、三次握手、四次握手(TCP Fast Open、正常情况、两边同时发起握手,详情参看:《再深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP》),加上tsl四次握手,quick一次握手建立通信是不是快的飞起?
改进的拥塞控制
TCP 的拥塞控制实际上包含了四个算法:慢启动,拥塞避免,快速重传,快速恢复。
QUIC 协议当前默认使用了 TCP 协议的 Cubic 拥塞控制算法,同时也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等拥塞控制算法
QUIC的NACK比TCP的延迟确认机制高效
TCP 为了保证可靠性,使用了基于字节序号的 Sequence Number 及 Ack 来确认消息的有序到达。
QUIC 同样是一个可靠的协议,它使用 Packet Number 代替了 TCP 的 sequence number,并且每个 Packet Number 都严格递增,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。而 TCP 呢,重传 segment 的 sequence number 和原始的 segment 的 Sequence Number 保持不变,也正是由于这个特性,引入了 Tcp 重传的歧义问题。
在普通的TCP里面,如果发送方收到三个重复的ACK就会触发快速重传,如果太久没收到ACK就会触发超时重传,而使用NACK可以直接告知发送方哪些包丢了,不用等到超时重传。TCP有一个SACK的选项,也具备NACK的功能,QUIC的NACK有一个区别它每次重传的报文序号都是新的。
但是单纯依靠严格递增的 Packet Number 肯定是无法保证数据的顺序性和可靠性。QUIC 又引入了一个 Stream Offset 的概念。
即一个 Stream 可以经过多个 Packet 传输,Packet Number 严格递增,没有依赖。但是 Packet 里的 Payload 如果是 Stream 的话,就需要依靠 Stream 的 Offset 来保证应用数据的顺序。如错误! 未找到引用源。所示,发送端先后发送了 Pakcet N 和 Pakcet N+1,Stream 的 Offset 分别是 x 和 x+y。
假设 Packet N 丢失了,发起重传,重传的 Packet Number 是 N+2,但是它的 Stream 的 Offset 依然是 x,这样就算 Packet N + 2 是后到的,依然可以将 Stream x 和 Stream x+y 按照顺序组织起来,交给应用程序处理。
FEC前向纠正拥塞控制
FEC是Forward Error Correction前向错误纠正的意思,就是通过多发一些冗余的包,当有些包丢失时,可以通过冗余的包恢复出来,而不用重传。这个算法在多媒体网关拥塞控制有重要的地位。QUIC的FEC是使用的XOR的方式,即发N + 1个包,多发一个冗余的包,在正常数据的N个包里面任意一个包丢了,可以通过这个冗余的包恢复出来,使用异或可以做到
切换网络操持连接
经常会有从4G切换到wifi网络或者是从wifi切换到4G网络的场景,由于网络的IP变了,导致需要重新建立连接,而QUIC使用一个ID来标志连接,即使切换网络也可以使用之前的建立连接的数据如交换的密钥,而不用再重新HTTPS握手,不过切换的过程可能会导致有些包丢了,需要利用FEC恢复或者重传。
不允许 Reneging
什么叫 Reneging 呢?就是接收方丢弃已经接收并且上报给 SACK 选项的内容 [8]。TCP 协议不鼓励这种行为,但是协议层面允许这样的行为。主要是考虑到服务器资源有限,比如 Buffer 溢出,内存不够等情况。
Reneging 对数据重传会产生很大的干扰。因为 Sack 都已经表明接收到了,但是接收端事实上丢弃了该数据。
QUIC 在协议层面禁止 Reneging,一个 Packet 只要被 Ack,就认为它一定被正确接收,减少了这种干扰。
更多的 Ack 块
TCP 的 Sack 选项能够告诉发送方已经接收到的连续 Segment 的范围,方便发送方进行选择性重传。
由于 TCP 头部最大只有 60 个字节,标准头部占用了 20 字节,所以 Tcp Option 最大长度只有 40 字节,再加上 Tcp Timestamp option 占用了 10 个字节 [25],所以留给 Sack 选项的只有 30 个字节。
每一个 Sack Block 的长度是 8 个,加上 Sack Option 头部 2 个字节,也就意味着 Tcp Sack Option 最大只能提供 3 个 Block。
但是 Quic Ack Frame 可以同时提供 256 个 Ack Block,在丢包率比较高的网络下,更多的 Sack Block 可以提升网络的恢复速度,减少重传量。
Ack Delay 时间
Tcp 的 Timestamp 选项存在一个问题 [25],它只是回显了发送方的时间戳,但是没有计算接收端接收到 segment 到发送 Ack 该 segment 的时间。这个时间可以简称为 Ack Delay。
这样就会导致 RTT 计算误差。如下图:
可以认为 TCP 的 RTT 计算:RTT = timestamp2 - timestamp1
而 Quic 计算如下:RTT = timestamp2 - timestamp1 - AckDelay
当然 RTT 的具体计算没有这么简单,需要采样,参考历史数值进行平滑计算,参考如下公式 :
SRTT = SRTT + α × (RTT - SRTT)
RTO = μ × SRTT + δ × DevRTT
基于 stream 和 connecton 级别的流量控制
QUIC 的多路复用和 HTTP2 类似。在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (stream)。但是 QUIC 的多路复用相比 HTTP2 有一个很大的优势。
QUIC 一个连接上的多个 stream 之间没有依赖。这样假如 stream2 丢了一个 udp packet,也只会影响 stream2 的处理。不会影响 stream2 之前及之后的 stream 的处理。
这也就在很大程度上缓解甚至消除了队头阻塞的影响。
多路复用是 HTTP2 最强大的特性,能够将多条请求在一条 TCP 连接上同时发出去。但也恶化了 TCP 的一个问题,队头阻塞,如下图示:
HTTP2 在一个 TCP 连接上同时发送 4 个 Stream。其中 Stream1 已经正确到达,并被应用层读取。但是 Stream2 的第三个 tcp segment 丢失了,TCP 为了保证数据的可靠性,需要发送端重传第 3 个 segment 才能通知应用层读取接下去的数据,虽然这个时候 Stream3 和 Stream4 的全部数据已经到达了接收端,但都被阻塞住了。
不仅如此,由于 HTTP2 强制使用 TLS,还存在一个 TLS 协议层面的队头阻塞 。
Record 是 TLS 协议处理的最小单位,最大不能超过 16K,一些服务器比如 Nginx 默认的大小就是 16K。由于一个 record 必须经过数据一致性校验才能进行加解密,所以一个 16K 的 record,就算丢了一个字节,也会导致已经接收到的 15.99K 数据无法处理,因为它不完整。
那 QUIC 多路复用为什么能避免上述问题呢?
QUIC 最基本的传输单元是 Packet,不会超过 MTU 的大小,整个加密和认证过程都是基于 Packet 的,不会跨越多个 Packet。这样就能避免 TLS 协议存在的队头阻塞;
Stream 之间相互独立,比如 Stream2 丢了一个 Pakcet,不会影响 Stream3 和 Stream4。不存在 TCP 队头阻塞。
当然,并不是所有的 QUIC 数据都不会受到队头阻塞的影响,比如 QUIC 当前也是使用 Hpack 压缩算法 [10],由于算法的限制,丢失一个头部数据时,可能遇到队头阻塞。
总体来说,QUIC 在传输大量数据时,比如视频,受到队头阻塞的影响很小。
更安全的传输协议
TCP 协议头部没有经过任何加密和认证,所以在传输过程中很容易被中间网络设备篡改,注入和窃听。比如修改序列号、滑动窗口。这些行为有可能是出于性能优化,也有可能是主动攻击。
但是 QUIC 的 packet 可以说是武装到了牙齿。除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。
这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。
如下图所示,红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。
这一切,归功于 UDP的不可靠 变为可靠。
如何部署QUIC
如今业界nginx打头阵(反向代理、负债均衡、转发)的头号代表(占统治地位),且看官方:
https://www.nginx.com/blog/nginx-f5-continued-commitment-open-source/
…………
And we’re not stopping there. Our plan for 2019 is to accelerate open source development with even more capabilities. Notable roadmap items include:
NGINX – QUIC and HTTP/3 implementations, as well as support for asynchronous file open
NGINX Unit – Java servlet containers, proxying capabilities, static file support
njs – Support for JavaScript modules (import/export) and deeper NGINX integrations
…………
现在上的话,就Canddy(监听UDP 443端口) 和nginx配合打法。
具体步骤,推荐 :《前卫一下:给你的网站开启 QUIC——https://www.bennythink.com/quic.html 》
推荐阅读:
https://blog.cloudflare.com/http3-the-past-present-and-future/
https://www.humanlevel.com/en/seo-posts/http-3-and-quic-what-do-they-mean-for-the-web.html
参考网站:
技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解 http://www.52im.net/thread-1309-1-1.html(非常详细)
怎样把网站升级到QUIC及QUIC特性分析 https://zhuanlan.zhihu.com/p/37919534
让互联网更快:新一代QUIC协议在腾讯的技术实践分享 https://www.cnblogs.com/jb2011/p/8458549.html
QUIC协议的分析,性能测试以及在QQ会员实践 https://wetest.qq.com/lab/view/384.html
转载本站文章《浅谈QUIC/http3协议原理与性能分析及部署方案》,
请注明出处:https://www.zhoulujun.cn/html/theory/ComputerScienceTechnology/network/2016_0217_5689.html