|
本文共计:5852字;阅读需要:15分钟;目录导语1.QUIC是啥?1.1什么是QUIC1.2HTTP协议发展 1.2.1HTTP历史进程 1.2.2HTTP1.0和HTTP1.1 1.2.3HTTP2 1.2.4HTTP3——QUIC2.QUIC的关键特性2.1连接迁移 2.1.1TCP连接重连之痛 2.1.2基于UDP的QUIC连接迁移实现2.2低连接延时 2.2.1TLS的连接时延问题 2.2.2真0-RTT的QUIC握手2.3可自定义的拥塞控制2.4无队头阻塞 2.4.1TCP的队头阻塞问题 2.4.2QUIC的无队头阻塞解决方案3.QUIC协议组成4.结语参考资料START导语QUIC,又名HTTP3,是近年来诞生的非常厉害的传输协议,它利用UDP解决了当前基于TCP协议的HTTP的许多问题,提升了在弱网环境下的网络通信体验。让我们来一探究竟!腾讯云CDN上周已支持QUIC协议,在官网产品文档即可找到内测申请链接及使用说明!1.1什么是QUIC?QUIC(QuickUDPInternetConnection)是谷歌推出的一套基于UDP的传输协议,它实现了TCP+HTTPS+HTTP/2的功能,目的是保证可靠性的同时降低网络延迟。因为UDP是一个简单传输协议,基于UDP可以摆脱TCP传输确认、重传慢启动等因素,建立安全连接只需要一的个往返时间,它还实现了HTTP/2多路复用、头部压缩等功能。众所周知UDP比TCP传输速度快,TCP是可靠协议,但是代价是双方确认数据而衍生的一系列消耗。其次TCP是系统内核实现的,如果升级TCP协议,就得让用户升级系统,这个的门槛比较高,而QUIC在UDP基础上由客户端自由发挥,只要有服务器能对接就可以。图1-1HTTP与QUIC1.2HTTP协议发展1.2.1HTTP历史进程◎HTTP0.9(1991年)只支持get方法不支持请求头;◎HTTP1.0(1996年)基本成型,支持请求头、富文本、状态码、缓存、连接无法复用;◎HTTP1.1(1999年)支持连接复用、分块发送、断点续传;◎HTTP2.0(2015年)二进制分帧传输、多路复用、头部压缩、服务器推送等;◎HTTP3.0(2018年)QUIC于2013年实现、2018年正式更名为HTTP3;1.2.2HTTP1.0和HTTP1.1◎队头阻塞:下个请求必须在前一个请求返回后才能发出,导致带宽无法被充分利用,后续请求被阻塞(HTTP1.1尝试使用流水线(Pipelining)技术,但先天FIFO(先进先出)机制导致当前请求的执行依赖于上一个请求执行的完成,容易引起队头阻塞,并没有从根本上解决问题);◎协议开销大:header里携带的内容过大,且不能压缩,增加了传输的成本;◎单向请求:只能单向请求,客户端请求什么,服务器返回什么;HTTP1.0和HTTP1.1的区别:HTTP1.0HTTP1.1仅支持保持短暂的TCP连接(连接无法复用)默认支持长连接(请求可复用TCP连接)不支持断点续传支持断点续传(通过在Header设置参数)前一个请求响应到达之后下一个请求才能发送,存在队头阻塞优化了缓存控制策略------管道化,可以一次发送多个请求,但是响应仍是顺序返回,仍然无法解决队头阻塞的问题------新增错误状态码通知------请求消息和响应消息都支持Host头域1.2.3HTTP2解决HTTP1的一些问题,但是解决不了底层TCP协议层面上的队头阻塞问题。1.二进制传输:二进制格式传输数据解析起来比文本更高效;2.多路复用:重新定义底层http语义映射,允许同一个连接上使用请求和响应双向数据流。同一域名只需占用一个TCP连接,通过数据流(Stream)以帧为基本协议单位,避免了因频繁创建连接产生的延迟,减少了内存消耗,提升了使用性能,并行请求,且慢的请求或先发送的请求不会阻塞其他请求的返回;3.Header压缩:减少请求中的冗余数据,降低开销;4.服务端可以主动推送:提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间;5.流优先级:数据传输优先级可控,使网站可以实现更灵活和强大的页面控制;6.可重置:能在不中断TCP连接的情况下停止数据的发送;缺点:HTTP2中,多个请求在一个TCP管道中的,出现了丢包时,HTTP2的表现反倒不如HTTP1.1了。因为TCP为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP2出现丢包时,整个TCP都要开始等待重传,那么就会阻塞该TCP连接中的所有请求。而对于HTTP1.1来说,可以开启多个TCP连接,出现这种情况反到只会影响其中一个连接,剩余的TCP连接还可以正常传输数据。1.2.4HTTP3——QUIC HTTP是建立在TCP协议之上,所有HTTP协议的瓶颈及其优化技巧都是基于TCP协议本身的特性,HTTP2虽然实现了多路复用,底层TCP协议层面上的问题并没有解决(HTTP2.0同一域名下只需要使用一个TCP连接。但是如果这个连接出现了丢包,会导致整个TCP都要开始等待重传,后面的所有数据都被阻塞了),而HTTP3的QUIC就是为解决HTTP2的TCP问题而生。关于QUIC的原理,相关介绍的文章很多,这里再列举一下QUIC的重要特性。这些特性是QUIC得以被广泛应用的关键。不同业务也可以根据业务特点利用QUIC的特性去做一些优化。同时,这些特性也是我们去提供QUIC服务的切入点。2.1连接迁移2.1.1TCP的连接重连之痛一条TCP连接是由四元组标识的(源IP,源端口,目的IP,目的端口)。什么叫连接迁移呢?就是当其中任何一个元素发生变化时,这条连接依然维持着,能够保持业务逻辑不中断。当然这里面主要关注的是客户端的变化,因为客户端不可控并且网络环境经常发生变化,而服务端的IP和端口一般都是固定的。比如大家使用手机在WIFI和4G移动网络切换时,客户端的IP肯定会发生变化,需要重新建立和服务端的TCP连接。又比如大家使用公共NAT出口时,有些连接竞争时需要重新绑定端口,导致客户端的端口发生变化,同样需要重新建立TCP连接。所以从TCP连接的角度来讲,这个问题是无解的。2.1.2基于UDP的QUIC连接迁移实现当用户的地址发生变化时,如WIFI切换到4G场景,基于TCP的HTTP协议无法保持连接的存活。QUIC基于连接ID唯一识别连接。当源地址发生改变时,QUIC仍然可以保证连接存活和数据正常收发。那QUIC是如何做到连接迁移呢?很简单,QUIC是基于UDP协议的,任何一条QUIC连接不再以IP及端口四元组标识,而是以一个64位的随机数作为ID来标识,这样就算IP或者端口发生变化时,只要ID不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。由于这个ID是客户端随机产生的,并且长度有64位,所以冲突概率非常低。图2-1TCP和QUIC在Wi-Fi和cellular切换时,唯一标识的不同情况2.2低连接延时2.2.1TLS的连接时延问题以一次简单的浏览器访问为例,在地址栏中输入https://www.abc.com,实际会产生以下动作:◎DNS递归查询www.abc.com,获取地址解析的对应IP;◎TCP握手,我们熟悉的TCP三次握手需要需要1个RTT;◎TLS握手,以目前应用最广泛的TLS1.2而言,需要2个RTT。对于非首次建连,可以选择启用会话重用,则可缩小握手时间到1个RTT;◎HTTP业务数据交互,假设abc.com的数据在一次交互就能取回来。那么业务数据的交互需要1个RTT;经过上面的过程分析可知,要完成一次简短的HTTPS业务数据交互,需要经历:新连接 4RTT+DNS;会话重用 3RTT+DNS。所以,对于数据量小的请求而言,单一次的请求握手就占用了大量的时间,对于用户体验的影响非常大。同时,在用户网络不佳的情况下,RTT延时会变得较高,极其影响用户体验。下图对比了TLS各版本与场景下的延时对比: 图2-2TLS各个版本握手时延从对比我们可以看到,即使用上了TLS1.3,精简了握手过程,最快能做到0-RTT握手(首次是1-RTT);但是对用户感知而言,还要加上1RTT的TCP握手开销。Google有提出Fastopen的方案来使得TCP非首次握手就能附带用户数据,但是由于TCP实现僵化,无法升级应用,相关RFC到现今都是experimental状态。这种分层设计带来的延时,有没有办法进一步降低呢?QUIC通过合并加密与连接管理解决了这个问题,我们来看看其是如何实现真正意义上的0-RTT的握手,让与server进行第一个数据包的交互就能带上用户数据。2.2.2真0-RTT的QUIC握手QUIC由于基于UDP,无需TCP连接,在最好情况下,短连接下QUIC可以做到0RTT开启数据传输。而基于TCP的HTTPS,即使在最好的TLS1.3的earlydata下仍然需要1RTT开启数据传输。而对于目前线上常见的TLS1.2完全握手的情况,则需要3RTT开启数据传输。对于RTT敏感的业务,QUIC可以有效的降低连接建立延迟。究其原因一方面是TCP和TLS分层设计导致的:分层的设计需要每个逻辑层次分别建立自己的连接状态。另一方面是TLS的握手阶段复杂的密钥协商机制导致的。要降低建连耗时,需要从这两方面着手。QUIC具体握手过程如下:1.客户端判断本地是否已有服务器的全部配置参数(证书配置信息),如果有则直接跳转到(5),否则继续;2.客户端向服务器发送inchoateclienthello(CHLO)消息,请求服务器传输配置参数;3.服务器收到CHLO,回复rejection(REJ)消息,其中包含服务器的部分配置参数;4.客户端收到REJ,提取并存储服务器配置参数,跳回到(1);5.客户端向服务器发送fullclienthello消息,开始正式握手,消息中包括客户端选择的公开数。此时客户端根据获取的服务器配置参数和自己选择的公开数,可以计算出初始密钥K1;6.服务器收到fullclienthello,如果不同意连接就回复REJ,同(3);如果同意连接,根据客户端的公开数计算出初始密钥K1,回复serverhello(SHLO)消息,SHLO用初始密钥K1加密,并且其中包含服务器选择的一个临时公开数;7.客户端收到服务器的回复,如果是REJ则情况同(4);如果是SHLO,则尝试用初始密钥K1解密,提取出临时公开数;8.客户端和服务器根据临时公开数和初始密钥K1,各自基于SHA-256算法推导出会话密钥K2;9.双方更换为使用会话密钥K2通信,初始密钥K1此时已无用,QUIC握手过程完毕。之后会话密钥K2更新的流程与以上过程类似,只是数据包中的某些字段略有不同。图2-3QUIC0-RTT 握手2.3可自定义的拥塞控制Quic使用可插拔的拥塞控制,相较于TCP,它能提供更丰富的拥塞控制信息。比如对于每一个包,不管是原始包还是重传包,都带有一个新的序列号(seq),这使得Quic能够区分ACK是重传包还是原始包,从而避免了TCP重传模糊的问题。Quic同时还带有收到数据包与发出ACK之间的时延信息。这些信息能够帮助更精确的计算RTT。此外,Quic的ACKFrame支持256个NACK区间,相比于TCP的SACK(SelectiveAcknowledgment)更弹性化,更丰富的信息会让client和server哪些包已经被对方收到。QUIC的传输控制不再依赖内核的拥塞控制算法,而是实现在应用层上,这意味着我们根据不同的业务场景,实现和配置不同的拥塞控制算法以及参数。GOOGLE提出的BBR拥塞控制算法与CUBIC是思路完全不一样的算法,在弱网和一定丢包场景,BBR比CUBIC更不敏感,性能也更好。在QUIC下我们可以根据业务随意指定拥塞控制算法和参数,甚至同一个业务的不同连接也可以使用不同的拥塞控制算法。图2-4BBR拥塞弱网下算法效果对比2.4无队头阻塞2.4.1TCP的队头阻塞问题虽然HTTP2实现了多路复用,但是因为其基于面向字节流的TCP,因此一旦丢包,将会影响多路复用下的所有请求流。QUIC基于UDP,在设计上就解决了队头阻塞问题。TCP队头阻塞的主要原因是数据包超时确认或丢失阻塞了当前窗口向右滑动,我们最容易想到的解决队头阻塞的方案是不让超时确认或丢失的数据包将当前窗口阻塞在原地。QUIC也正是采用上述方案来解决TCP队头阻塞问题的。TCP为了保证可靠性,使用了基于字节序号的SequenceNumber及Ack来确认消息的有序到达。图2-5HTTP2队头阻塞如上图,应用层可以顺利读取stream1中的内容,但由于stream2中的第三个segment发生了丢包,TCP为了保证数据的可靠性,需要发送端重传第3个segment才能通知应用层读取接下去的数据。所以即使stream3stream4的内容已顺利抵达,应用层仍然无法读取,只能等待stream2中丢失的包进行重传。在弱网环境下,HTTP2的队头阻塞问题在用户体验上极为糟糕。2.4.2QUIC的无队头阻塞解决方案QUIC同样是一个可靠的协议,它使用PacketNumber代替了TCP的SequenceNumber,并且每个PacketNumber都严格递增,也就是说就算PacketN丢失了,重传的PacketN的PacketNumber已经不是N,而是一个比N大的值,比如PacketN+M。QUIC使用的PacketNumber单调递增的设计,可以让数据包不再像TCP那样必须有序确认,QUIC支持乱序确认,当数据包PacketN丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动。待发送端获知数据包PacketN丢失后,会将需要重传的数据包放到待发送队列,重新编号比如数据包PacketN+M后重新发送给接收端,对重传数据包的处理跟发送新的数据包类似,这样就不会因为丢包重传将当前窗口阻塞在原地,从而解决了队头阻塞问题。那么,既然重传数据包的PacketN+M与丢失数据包的PacketN编号并不一致,我们怎么确定这两个数据包的内容一样呢?QUIC使用StreamID来标识当前数据流属于哪个资源请求,这同时也是数据包多路复用传输到接收端后能正常组装的依据。重传的数据包PacketN+M和丢失的数据包PacketN单靠StreamID的比对一致仍然不能判断两个数据包内容一致,还需要再新增一个字段StreamOffset,标识当前数据包在当前StreamID中的字节偏移量。有了StreamOffset字段信息,属于同一个StreamID的数据包也可以乱序传输了(HTTP/2中仅靠StreamID标识,要求同属于一个StreamID的数据帧必须有序传输),通过两个数据包的StreamID与StreamOffset都一致,就说明这两个数据包的内容一致。图2-6QUIC无队头阻塞QUIC的packet除了个别报文比如PUBLIC_RESET和CHLO,所有报文头部都是经过认证的,报文Body都是经过加密的。这样只要对QUIC报文任何修改,接收端都能够及时发现,有效地降低了安全风险。如图3-1所示,红色部分是StreamFrame的报文头部,有认证。绿色部分是报文内容,全部经过加密。图3-1QUIC的协议组成◎Flags:用于表示ConnectionID长度、PacketNumber长度等信息;◎ConnectionID:客户端随机选择的最大长度为64位的无符号整数。但是,长度可以协商;◎QUICVersion:QUIC协议的版本号,32位的可选字段。如果PublicFlag&FLAG_VERSION!=0,这个字段必填。客户端设置PublicFlag中的Bit0为1,并且填写期望的版本号。如果客户端期望的版本号服务端不支持,服务端设置PublicFlag中的Bit0为1,并且在该字段中列出服务端支持的协议版本(0或者多个),并且该字段后不能有任何报文;◎PacketNumber:长度取决于PublicFlag中Bit4及Bit5两位的值,最大长度6字节。发送端在每个普通报文中设置PacketNumber。发送端发送的第一个包的序列号是1,随后的数据包中的序列号的都大于前一个包中的序列号;◎StreamID:用于标识当前数据流属于哪个资源请求;◎Offset:标识当前数据包在当前StreamID中的字节偏移量;QUIC报文的大小需要满足路径MTU的大小以避免被分片。当前QUIC在IPV6下的最大报文长度为1350,IPV4下的最大报文长度为1370。QUIC具有众多优点,它融合了UDP协议的速度、性能与TCP的安全与可靠,同时也解决了HTTP1、HTTP1.1、HTTP2中引入的一些缺点,大大优化了互联网传输体验。腾讯云CDN也紧跟技术浪潮,于今年年初迭代中加入了QUIC的功能支持,目前正在内测当中。扫码可以申请内测资格&查看文档指引哦~ 申请内测 文档指引 参考资料[1]QUIC在Facebook是如何部署的?[2] STGW下一代互联网标准传输协议QUIC大规模运营之路 [3]QUIC0-RTT实现简析及一种分布式的0-RTT实现方案[4]科普:QUIC协议原理分析[5]TCPBBR-ExploringTCPcongestioncontrol[6]浅谈QUIC协议原理与性能分析及部署方案[7]QUIC是如何解决TCP性能瓶颈的?[8]QUIC协议和TCP/UDP协议[9]QUIC的那些事|包类型及格式Spring扫码关注收获更多~我知道你在看哟
|
|