技术素养:新一代基于UDP的低延迟网络传输层协议——Quic详细说明

时间:2020-10-20

语音会议源码


 1.写在前面

 如果你的应用不需要任何修改,它可以提高15%以上的访问速度。特别是在网络薄弱的时候,接入速度可以提高20%以上。

 如果你的应用经常在4G和WIFI网络之间切换,它就不会被断开,也不需要重新连接,用户也不会有任何感觉。如果您的应用程序同时需要TLS安全性和HTTP2多路复用。

 如果您刚刚听说了HTTP2是下一代互联网协议,如果您刚刚注意到TLS1.3是一个革命性的里程碑式的协议,那么这两个协议已经受到了另一个新兴协议的影响和挑战。

 如果这种新的协议正在出现,它的名字就叫“快”,并且它正在被标准化为新一代的互联网传输协议。

 你愿意花一点时间来理解这个协议吗?你愿意致力于研究这个协议吗?你愿意推动企业使用这个协议吗?

 建议:如果你觉得这篇文章有点难懂,你可以读一下《网络编程懒惰导论》(10):到了泡尿的时候了,赶快理解QUIC协议。

 2.相关文章

 网络编程中的懒人入门(10):泡在尿里的时候,快速理解quic协议

 技术素养:新一代基于UDP的低延迟网络传输层协议

 让互联网更快:分享腾讯新一代QUIC协议的技术实践

 “七牛云技术共享:用QUIC协议实现实时视频直播0卡住了!》

 3.这篇文章的作者

 技术素养:基于UDP的新一代低延迟网络传输层协议——quic详细说明_ 6ca20203jw1e8qgp5bmzyj2050050aa8.jpg

 罗成:腾讯R&D高级工程师。目前,他主要负责腾讯stgw(腾讯安全云网关)的相关工作,统筹推进腾讯内部、腾讯公共云和混合云的七层负载均衡以及全站HTTPS接入。对HTTPS、SPDY、HTTP2、QUIC等应用层协议、高性能服务器技术、云网络技术、用户访问速度、分布式文件传输等有深入的了解。(作者微博:点击此处进入)

 4.QUIC协议概述

 技术素养:新一代基于UDP的低延迟网络传输层协议——quic详细说明_ x1.jpg。

 Quic的全称是快速udp互联网连接[1],“快速udp互联网连接”(与英语quick谐音,称为“quick”)是由谷歌提出的一种协议,它使用UDP进行多路传输和并发传输。

 与广泛使用的http2+tcp+tls协议相比,Quic具有以下优势[2]:

 减少了TCP三次握手和TLS的握手时间;

 改善拥塞控制:

 避免被队列头阻塞的多路复用;

 连接迁移;

 前向冗余纠错。

 下图是网络层比较图:

 技术素养:基于UDP-Quic的新一代低延迟网络传输层协议详细解释了_WX20180104-122733@2x.png

 下图是通信延迟的比较图:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 5.你为什么需要QUIC

 5.1概述

 自20世纪90年代互联网兴起以来,大多数互联网流量传输只使用少数网络协议。IPv4用于路由,TCP用于连接级流量控制,SSL/TLS协议用于传输安全,DNS用于域名解析,HTTP用于应用数据传输。

 近三十年来,这些协议的发展非常缓慢。TCP主要是拥塞控制算法的改进,SSL/TLS基本保持不变,而几个小的改动主要是密码套件的升级。TLS1.3[3]是一个跨越式的变化,但迄今为止,它尚未正式发布。尽管IPv4已经取得了很大的进步,实现了IPv6并为DNS添加了一个安全的DNSSEC,但是部署进度和IPv6一样缓慢。

 随着移动互联网的快速发展和物联网的逐渐兴起,网络交互的场景越来越丰富,网络传输的内容越来越庞大,用户对网络传输效率和网络响应速度有了更高的要求。

 一方面,它是一个历史悠久、用途广泛的古老礼仪;另一方面,用户的使用场景要求越来越高的传输性能。

 下列长期存在的问题和矛盾越来越突出:

 协议的长期历史导致了中间设备的刚性;

 依赖于操作系统的实现导致协议本身的刚性;

 建立连接的握手延迟大;

 组长被封锁了。

 这是一个分章节的简要解释。

 5.2中间设备的刚度

 这可能是因为TCP使用时间太长,而且非常可靠。因此,我们的许多中间设备,包括防火墙、NAT网关、整流器等等,都有一些常规操作。

 例如,一些防火墙只允许访问80和443端口,而不允许访问其他端口。NAT网关在转换网络地址时会重写传输层的报头,这可能会导致双方都无法使用新的传输格式。出于安全原因,整流器和中间代理有时会删除一些未知的选项字段。

 TCP协议最初支持端口、选项和功能的添加和修改。然而,由于TCP协议和众所周知的端口和选项已经被使用了很长时间,中间设备已经依赖于这些隐藏的规则,所以这些内容的修改很容易被中间链路干扰并失败。

 这些干扰也导致对TCP协议的大量优化变得谨慎和困难。

 5.3根据操作系统的实现,协议变得僵化

 TCP是由操作系统在内核西部堆栈层实现的,它只能由应用程序使用,不能直接修改。尽管应用程序的更新迭代非常快速简单。然而,TCP的迭代非常慢,因为升级操作系统很麻烦。

 如今,移动终端越来越受欢迎,但一些移动用户的操作系统升级可能仍会滞后几年。个人电脑方面的系统升级严重滞后,尽管windows xp已经存在了近20年,但仍被大量用户使用。

 服务器系统不依赖于用户升级,但是因为操作系统升级涉及到更新底层软件和运行时,所以它也是保守和缓慢的。

 这意味着即使TCP有更好的特性更新,也很难快速推广。例如,TCP快速打开。尽管它是在2013年提出的,但许多版本的Windows仍然不支持它。

 5.4建立连接的握手延迟很大

 无论是HTTP1.0/1.1、HTTPS还是HTTP2,TCP都是用于传输的。HTTPS和HTTP2也需要TLS协议来实现安全传输。

 这导致两次握手延迟:

 1)TCP三次握手造成的TCP连接建立延迟;

 2)TLS完整握手至少需要建立2个RTT,简化握手需要1个RTT握手延迟。

 对于许多短连接情况,这种握手延迟影响很大,无法消除。

 5.5组长受阻

 队列头阻塞主要是由TCP协议的可靠性机制引入的。TCP使用序列号来识别数据的顺序,数据必须按顺序处理。如果先前的数据丢失,即使后续数据到达,也不会通知应用层进行处理。

 此外,在TLS协议级有一个队列头块,因为TLS协议根据记录处理数据,如果记录中的数据丢失,整个记录就不能被正确处理。

 总的来说,TCP和TLS1.2之前的协议存在结构性问题。如果我们继续在现有的TCP和TLS协议的基础上实现一个全新的应用层协议,它将依赖于操作系统、中间件和用户的支持。部署成本非常高,阻力非常大。

 因此,QUIC协议选择了UDP,因为UDP本身没有连接的概念,不需要三次握手,这优化了连接建立的握手延迟。同时,在应用层实现了TCP的可靠性、TLS的安全性和HTTP2的并发性,只需要客户端和服务器端的应用程序来支持QUIC协议,完全避免了操作系统和中间设备的限制。

 6.QUIC核心功能

 6.1连接建立延迟低

 与HTTP2相比,0RTT连接可以说是QUIC最大的性能优势。那么什么是0RTT公司?

 这有两个意思:

 传输层可以建立连接;

 加密层0RTT可以建立加密连接。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图1 HTTPS和QUIC的连接过程

 例如,上图左侧是HTTPS完整的握手建立过程,需要3个即时通信终端。即使会话恢复[14]也需要至少2个RTT。

 QUIC呢?由于它基于UDP协议,同时实现了0RTT的安全握手,所以在大多数情况下,只需要0RTT就可以实现数据传输。基于前向加密[15],0 RTT的成功率远高于TLS地震票证[13]。

 6.2改善拥塞控制

 TCP拥塞控制实际上包括四种算法:慢启动、拥塞避免、快速重传和快速恢复[22]。

 默认情况下,QUIC协议目前使用的是三次拥塞控制算法,并且还支持三次字节、雷诺、雷诺字节、BBR、PCC等拥塞控制算法。

 从拥塞算法本身来看,QUIC只是根据TCP协议重新实现的,那么QUIC协议的改进在哪些方面呢?主要有以下几点。

 [可插拔]:

 什么是可插拔的?就是能够非常灵活地生效、改变和停止。体现在以下几个方面:

 1)不同的拥塞控制算法可以在应用层实现,无需操作系统或内核支持。这是一个飞跃,因为传统的TCP拥塞控制必须得到端到端网络协议栈的支持才能达到控制效果。但是,内核和操作系统的部署成本很高,升级周期很长,显然不能满足当今产品快速迭代和网络爆炸式增长的需求;

 2)即使单个应用程序的不同连接也可以支持配置不同的拥塞控制。即使它是一个服务器,连接到它的用户的网络环境也有很大的不同。结合大数据和人工智能处理,我们可以为每个用户提供不同但更准确和有效的拥塞控制。例如,BBR是合适的,立方是合适的;

 3)应用程序可以在不停止或升级的情况下改变拥塞控制。我们只需要修改配置并在服务器端重新加载它,并且我们可以在根本不停止服务的情况下切换拥塞控制。

 STGW在配置级别进行了优化。我们可以对不同的服务、不同的网络标准甚至不同的RTT使用不同的拥塞控制算法。

 [单调递增的包号]:

 为了保证可靠性,TCP使用基于字节数的序列号和确认来确认消息的有序到达。

 QUIC也是一个可靠的协议,它使用包号代替Tcp序列号,并且每个包号都严格增加,也就是说,即使包N丢失,重传包N的包号也不是N,而是大于N的值。对于TCP,重传段的序列号和原始段的序列号保持不变。正是由于这一特点,引入了TCP重传的模糊性。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图2传输控制协议重传的模糊性

 如上图所示,在超时事件RTO发生后,客户端发起重传,然后接收Ack数据。由于序列号相同,这个Ack数据是对原始请求的响应还是对重传请求的响应?很难判断。

 如果它被计为原始请求的响应,但实际上它是重传请求的响应(上图中的左边),采样RTT将变得更大。如果将其算作重传请求的响应,但实际上是原始请求的响应,很容易导致采样RTT值过小。

 由于快速重传包和原始包的包数严格增加,这个问题很容易解决。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图3快速重传没有歧义

 如上图所示,在实时操作发生后,可以根据重传的包号来确定准确的RTT计算。如果ack的包号为N+M,则根据重传请求计算采样RTT。如果确认的帕克塞数为n,则根据最初请求的时间计算采样RTT,并且没有歧义。

 然而,仅仅通过严格增加包号来保证数据的顺序和可靠性是绝对不可能的。QUIC引入了流偏移的概念。

 也就是说,一个流可以通过多个分组来传输,并且分组号被严格地增加而没有依赖性。但是如果包中的有效载荷是流,它需要依赖流的偏移量来保证应用数据的顺序。比如错误!找不到参考源。如图所示,发送方先后发送了数据包n和数据包n+1,流的偏移量分别为x和x+y。

 假设分组N丢失,重传开始,重传的分组号是N+2,但是其流的偏移量仍然是x,所以即使分组N+2迟了,流x和流x+y仍然可以按顺序组织,并移交给应用程序进行处理。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图4流偏移保证订单

 [不允许反悔]:

 什么是食言?也就是说,接收者丢弃已经接收并报告给SACK选项[8]的内容。TCP协议不鼓励这种行为,但在协议级别上是允许的。主要考虑服务器资源有限,如缓冲区溢出、内存不足等。

 反悔会对数据重传造成很大的干扰。因为Sack已经表示它已经被接收,但是接收者实际上丢弃了数据。

 QUIC禁止在协议级别进行更新,一旦数据包被确认,就认为它必须被正确接收,从而减少了这种干扰。

 [更多Ack块]:

 TCP的Sack选项可以告诉发送方接收到的连续段的范围,方便发送方进行选择性重传。

 TCP选项的最大长度只有40字节,因为Tcp报头的最大长度只有60字节,而标准报头占用20字节。此外,Tcp时间戳选项占用10个字节,因此只有30个字节保留给Sack选项。

 每个Sack块的长度是8,加上Sack选项的头2字节,这意味着Tcp Sack选项最多只能提供3个块。

 然而,快速确认帧可以同时提供256个确认块。在丢包率较高的网络中,增加Sack块可以提高网络的恢复速度,减少重传量。

 [确认延迟时间]:

 Tcp的时间戳选项[25]有一个问题,它只回显发送者的时间戳,但不计算从接收数据段到向接收者发送Ack的时间。这个时间可以简称为确认延迟。

 这将导致RTT计算错误。下图:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 可以认为,RTT计算的传输控制协议:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 Quic计算如下:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 当然,RTT的具体计算并不简单,所以需要抽样,并参照历史价值进行平滑计算。参考以下公式[9]:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 6.3基于流和连接级别的流量控制

 QUIC [22]的流控制类似于HTTP2,也就是说,它在连接和流级别提供两种流控制。为什么需要两种流量控制?主要是因为QUIC支持多路复用。

 流可以被视为一个HTTP请求。

 连接可以与TCP连接相比较。多路复用意味着一个连接上有多个流。有必要控制单个流和所有流作为一个整体。

 QUIC实现流量控制的原理很简单:

 告诉对方它可以通过window_update帧接收的字节数,这样发送方就不会发送超过这个数目的数据。

 通过块帧告诉另一端,由于流量控制被阻止,数据无法发送。

 QUIC的流量控制与TCP有些不同。为了确保TCP的可靠性,窗口左边缘向右滑动的长度取决于确认的字节数。如果数据包在中间丢失,即使收到序列号更大的数据段,该窗口也不能超过该序列号。

 然而,QUIC是不同的。即使以前没有接收到某些数据包,它的滑动也只取决于接收到的最大偏移字节数。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图5快速流量控制

 对于流:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 对于连接:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 同样,STGW在连接和流级别设置了不同的窗口。

 最重要的是,当内存不足或上游处理性能出现问题时,我们可以通过流量控制来限制传输速率,以确保服务的可用性。

 6.4无队列头阻塞的多路复用

 QUIC的多路复用类似于HTTP2。多个HTTP请求(流)可以在一个QUIC连接上并发发送。然而,QUIC的多路复用比HTTP2有很大的优势。

 QUIC,一个连接上多个流之间没有依赖性。这样,如果stream2丢失了一个udp数据包,它只会影响stream2的处理。它不影响流2前后的流处理。

 这在很大程度上减轻甚至消除了团队头阻塞的影响。

 多路复用是HTTP2 [7]最强大的功能,它可以在一个TCP连接上同时发送多个请求。但它也加剧了TCP的问题,队列头阻塞[11],如下图所示:

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图6 HTTP2团队负责人阻塞

 HTTP2在一个TCP连接上同时发送四个流。其中Stream1已经正确到达并被应用层读取。然而,流2的第三个tcp段丢失了。为了确保数据的可靠性,TCP需要发送方重新发送第三个数据段,以通知应用层读取下一个数据。虽然此时流3和流4的所有数据都已到达接收器,但它们被阻止。

 不仅如此,因为HTTP2强制TLS,所以在TLS协议级别有一个队列头块[12]。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图7张力腿系统团队负责人阻塞

 记录是TLS协议处理的最小单位,最大大小不能超过16K。一些服务器的默认大小是16K,例如Nginx。因为记录只能在数据一致性检查后进行加密和解密,所以即使16K记录丢失一个字节,也无法处理接收到的15.99K数据,因为它是不完整的。

 那么为什么QUIC复用可以避免上述问题呢?

 1)QUIC最基本的传输单元是数据包,它不会超过MTU的大小。整个加密和身份验证过程基于数据包,不会跨越多个数据包。这样,可以避免TLS协议的队列头阻塞;

 2)流彼此独立。例如,如果流2丢失一个数据包,它将不会影响流3和流4。没有TCP队列头阻塞。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 ▲图8在QUIC复用期间没有队列头阻塞的问题

 当然,不是所有的QUIC数据都不会受到队列头阻塞的影响。例如,QUIC目前使用Hpack压缩算法[10]。由于算法的限制,当头数据丢失时,可能会遇到队列头阻塞。

 一般来说,当传输大量数据(如视频)时,QUIC几乎不受队列头阻塞的影响。

 6.5加密和认证的消息

 TCP协议报头未经加密和认证,因此在传输过程中很容易被中间网络设备篡改、注入和窃听。例如修改序列号和滑动窗口。这些行为可能是由于性能优化,也可能是主动攻击。

 但是QUIC的包裹武装到了牙齿。除了单独的消息,如PUBLIC_RESET和CHLO,所有消息头都经过身份验证,消息体也经过加密。

 这样,只要QUIC消息被修改,接收者就能及时发现,有效降低了安全风险。

 如下图所示,红色部分是带身份验证的流帧的消息头。绿色部分是消息内容,全部加密。

 技术素养:新一代基于UDP的低延迟网络传输层协议

 6.6连接迁移

 一个TCP连接[17]由四个部分(源IP、源端口、目的IP、目的端口)标识。什么是连接迁移?也就是说,当任何一个元素改变时,这个连接仍然保持,这可以保持业务逻辑不中断。当然,这里主要关心的是客户端的变化,因为客户端是不可控的,网络环境经常变化,而服务器的IP和端口通常是固定的。

 例如,当您使用手机在WIFI和4G移动网络之间切换时,客户端的IP肯定会发生变化,因此您需要重新建立与服务器的TCP连接。

 例如,当人们使用公共网络地址转换出口时,一些连接需要在竞争时重新绑定端口,这导致客户端的端口发生变化,并且还需要重新建立TCP连接。

 针对TCP连接的变化,MPTCP[5]实际上有一个解决方案,但是因为MPTCP需要操作系统和网络协议栈的支持,部署阻力很大,目前还不适用。

 因此,从TCP连接的角度来看,这个问题是无法解决的。

 那么QUIC如何进行连接迁移呢?很简单,任何QUIC连接不再由IP和端口四元组来标识,而是由64位随机数来标识,因此即使IP或端口发生变化,只要ID保持不变,该连接仍将保持,并且上层业务逻辑将不会意识到该变化,也不会被中断,因此不需要重新连接。

 因为该标识是由客户端随机生成的,长度为64位,所以冲突概率非常低。

 6.7其他亮点

 此外,QUIC还可以实现前向冗余纠错,当握手消息等重要数据包丢失时,可以根据冗余信息恢复握手消息。

 QUIC还可以实现证书压缩,减少证书传输量,验证数据包报头。