当前位置: 首页 > 科技观察

HTTP-3来了!未来可期

时间:2023-03-12 13:28:07 科技观察

2015年HTTP/2标准发布后,大多数主流浏览器也在当年年底支持了该标准。此后,凭借多路复用、报头压缩、服务器推送等优势,HTTP/2受到了越来越多开发者的青睐,不知不觉中HTTP已经发展到了第三代。本文基于兴趣部落接入HTTP/3的实践,谈谈HTTP/3的原理和业务接入方式。一、HTTP/3的原理1.1HTTP的历史在介绍HTTP/3之前,我们先简单回顾一下HTTP的历史,了解一下HTTP/3的背景。随着网络技术的发展,1999年设计的HTTP/1.1已经不能满足需求,于是谷歌在2009年设计了基于TCP的SPDY,后来SPDY的开发团队推动SPDY成为官方标准,但未能成功结尾。但是SPDY的开发团队参与了HTTP/2的开发过程,参考了SPDY的很多设计,所以我们一般认为SPDY就是HTTP/2的前身。SPDY和HTTP/2都是基于TCP的。与UDP相比,TCP在效率上有天然的劣势。因此,在2013年,谷歌开发了一种基于UDP的传输层协议,称为QUIC。QUIC的全称是QuickUDPInternetConnections。它可以替代TCP,使网页传输更加高效。经过提案,InternetEngineeringTaskForce正式将基于QUIC协议的HTTP(HTTPoverQUIC)更名为HTTP/3。1.2QUIC协议概述TCP一直是传输层的重要协议,而UDP则鲜为人知。说到TCP和UDP的区别,关于UDP的答案往往很少。长期以来,UDP给人的印象是它是一种快速但不可靠的传输层协议。但有时从另一个角度来看,缺点也可能是优点。QUIC(QuickUDPInternetConnections,快速UDP网络连接)基于UDP,是基于UDP的速度和效率。同时,QUIC还综合了TCP、TLS和HTTP/2的优点并进行了优化。一张图就可以清楚地显示出它们之间的关系。那么QUIC和HTTP/3是什么关系呢?QUIC是用来替代TCP、SSL/TLS的传输层协议,在传输层之上还有一个应用层。众所周知的应用层协议有HTTP、FTP、IMAP等,而这些协议理论上都可以运行在QUIC之上,其中运行在QUIC之上的HTTP协议称为HTTP/3,也就是“HTTP”的意思通过QUIC或HTTP/3”。因此,要想了解HTTP/3,就绕不开QUIC。下面主要通过几个重要的特性让大家对QUIC有更深入的了解。1.3零RTT连接建立HTTP/2和HTTP/3连接建立的区别可以用一张图直观的看出来。HTTP/2连接需要3个RTT。如果考虑会话重用,即缓存第一次握手计算的对称密钥,那么还需要2个RTT。此外,如果TLS升级到1.3,那么HTTP/2连接需要2个RTT,考虑会话多路复用需要1个RTT。有人会说HTTP/2不一定需要HTTPS,可以简化握手过程。这很好,HTTP/2标准不需要基于HTTPS,但实际上所有的浏览器实现都要求HTTP/2必须基于HTTPS,所以HTTP/2加密连接必不可少。但是HTTP/3第一次连接只需要1个RTT,后面的连接只需要0个RTT,也就是说客户端发送给服务端的第一个数据包就包含了请求数据,这是HTTP/2很难做到的。那么这背后的原理是什么?下面详细看一下QUIC的连接过程。Step1:第一次连接时,客户端向服务端发送InchoateClientHello请求连接;Step2:服务端生成g、p、a,根据g、p、a计算出A,然后将g、p、A放入InServerConfig中,向客户端发送Rejection消息;Step3:客户端收到g,p,A后,再次生成b,根据g,p,b计算出B,根据A,p,b计算出初始密钥K。计算出B和K后,客户端会用K加密HTTP数据,与B一起发送给服务器;Step4:服务端收到B后,根据a、p、B生成与客户端相同的密钥,然后用这个密钥解密传入的HTTP数据。为了进一步的安全(前向安全),服务端会更新自己的随机数a和公钥,生成新的密钥S,然后通过ServerHello将公钥发送给客户端。与ServerHello消息一起,还有HTTP返回数据;Step5:客户端收到ServerHello后,生成一个新的与服务器一致的密钥S,后续的传输都用S加密。这样QUIC从请求连接到正式发送总共花费了1个RTT,接收HTTP数据。这1个RTT主要是获取ServerConfig。RTT建立连接。这里使用DH密钥交换算法。DH算法的核心是服务器产生3个随机数a、g、p。a自己持有,g和p传给客户端。随机数,客户端和服务器可以通过DH算法计算出相同的密钥。在这个过程中,a和b不参与网络传输,安全性大大提高。因为p和g都是大数,即使网络中传输的p、g、A、B全部被劫持,以目前的计算机计算能力也无法破解密钥。1.4连接迁移TCP连接基于四元数(源IP、源端口、目的IP、目的端口)。切换网络时,至少有一个因素会发生变化,从而导致连接发生变化。当连接发生变化时,如果仍然使用原来的TCP连接,连接就会失败,必须在原来的连接超时后重新建立连接,所以我们有时会发现,当切换到新的网络时,即使新的网络状况良好,但内容仍然需要很长时间才能加载。如果实施得好,当检测到网络变化时,会立即建立新的TCP连接,即便如此,建立新连接仍需要数百毫秒。QUIC的连接不受四元组的影响。当这四个元素发生变化时,原来的连接仍然保持。那么这是怎么做到的呢?原因很简单,QUIC连接没有使用四元组作为标识,而是使用了一个64位的随机数,这个随机数叫做ConnectionID,即使IP或者端口发生变化,只要ConnectionID不变,仍然可以保持连接。1.5线头阻塞/多路复用HTTP/1.1和HTTP/2都存在线头阻塞(Headoflineblocking)的问题,那么什么是线头阻塞呢?TCP是面向连接的协议,即发送请求后需要收到ACK报文,确认对方已收到数据。如果每一个请求都必须在收到上一个请求的ACK报文后才去请求,效率无疑是很低的。后来HTTP/1.1提出了Pipelining技术,允许一个TCP连接同时发送多个请求,大大提高了传输效率。在此背景下,让我们谈谈HTTP/1.1的队头阻塞。下图中,一个TCP连接同时传输了10个请求。其中第1、2、3个请求已经被客户端接收到,但是第4个请求丢失了,那么第5-10个请求都被阻塞了,需要等待第1个请求。只有处理完4个请求才能处理,浪费带宽资源。因此,HTTP一般允许每台主机建立6个TCP连接,可以充分利用带宽资源,但每个连接中队头阻塞的问题仍然存在。HTTP/2的多路复用解决了上述的队头阻塞问题。与HTTP/1.1不同的是,只有前一个请求的数据包都传输完了,才能传输下一个请求的数据包。在HTTP/2中,每个请求被分成多个Frames,通过TCP连接同时传输,这样即使一个请求被阻塞,也不会影响其他请求。如下图所示,不同的颜色代表不同的请求,相同颜色的色块代表请求被分割成的帧。事情还没有结束。虽然HTTP/2可以解决“请求”粒度的阻塞,但是HTTP/2的基础TCP协议也存在队头阻塞的问题。HTTP/2的每个请求都会被拆分成多个Frames,不同请求的Frames组合成一个Stream,Stream是TCP上的一个逻辑传输单元,这样HTTP/2就达到了在一个连接上同时发送多个请求的目的,这就是多路复用的原理。看个例子,在一个TCP连接上同时发送4个Streams,其中Stream1已经正确投递,Stream2中第三个Frame丢失,TCP有严格的数据处理顺序,先发送的Frame必须被处理first,这将要求发送方重新发送第三帧。Stream3和Stream4虽然到了但是无法处理,那么此时整个连接就被阻塞了。不仅如此,因为HTTP/2必须使用HTTPS,而HTTPS使用的TLS协议也存在队头阻塞的问题。TLS根据Record组织数据,将一堆数据加密在一起(即一个Record),加密后拆分成多个TCP包传输。一般每个Record都是16K,包含12个TCP包,所以如果这12个TCP包中的任何一个丢失,都无法解密整条Record。队头阻塞会导致HTTP/2在更容易丢包的弱网络环境下比HTTP/1.1慢!那么QUIC是如何解决队头阻塞问题的呢?主要有两点。QUIC的传输单位是Packet,加密单位也是Packet。整个加密、传输、解密都基于Packet,可以避免TLS的head-of-lineblocking问题;QUIC基于UDP,接收端不处理UDP包。如果一个数据包丢失,整个连接不会被阻塞,其他资源会正常处理。1.6拥塞控制拥塞控制的目的是避免过多的数据一次性涌入网络,导致网络超过最大负载。QUIC的拥塞控制类似于TCP,在此基础上进行了改进。那么我们先简单介绍一下TCP拥塞控制。TCP拥塞控制由4个核心算法组成:慢启动、拥塞避免、快速重传和快速恢复。了解了这4种算法,你就会对TCP拥塞控制有个大概的了解。慢启动:发送方向接收方发送1个单位的数据,收到对方确认后,再发送2个单位的数据,然后是4个、8个等,呈指数增长。这个过程不断地检测网络的拥塞度,超过阈值就会导致网络拥塞;拥塞避免:指数增长不可能无限大,达到一定限度(慢启动阈值)后,指数增长变为线性增长;快速重传:发送方发送一个超时定时器会被设置。超时后视为丢失,需要重新发送;快速恢复:在上述快速重传的基础上,当发送方重新发送数据时,也会启动一个超时定时器。如果收到确认消息,则进入拥塞避免阶段,如果仍然超时,则回到慢启动阶段。QUIC重新实现了TCP协议的Cubic算法进行拥塞控制,并在此基础上做了很多改进。QUIC改进的拥塞控制的一些特性描述如下。1.6.1如果要修改hot-plugTCP中的拥塞控制策略,需要在系统层面进行操作。QUIC只需要运行在应用层修改拥塞控制策略,QUIC会根据不同的网络环境和用户动态选择拥塞控制算法。1.6.2前向纠错FECQUIC采用前向纠错(FEC,ForwardErrorCorrection)技术来增加协议的容错能力。一个数据被分成10个数据包后,依次对每个数据包进行异或运算,运算结果将作为FEC数据包与数据包一起传输。剩下的9个包和FEC包计算丢失包的数据,大大增加了协议的容错性。这是一种符合当前网络技术的解决方案。现阶段带宽不是网络传输的瓶颈,往返时间才是。因此,新的网络传输协议可以适当增加数据冗余,减少重传操作。1.6.3PacketNumber单调递增为了保证可靠性,TCP使用SequenceNumber和ACK来确认报文是否按顺序到达,但这种设计存在缺陷。超时后客户端发起重传,后来收到ACK确认报文,但是由于原请求和重传请求收到的是同一个ACK报文,客户端郁闷,不知道这个ACK是否对应原来的请求或重传询问。如果client认为是原始请求的ACK,但实际上是左边的情况,说明计算的采样RTT偏大;如果client认为是重传请求的ACK,但实际上是右边的情况,会导致SamplingRTT太小。图中有几个术语。RTO指的是重传超时时间(RetransmissionTimeOut),与大家熟悉的RTT(RoundTripTime,往返时间)非常相似。采样RTT会影响RTO的计算。准确把握超时时间很重要,太长或太短都不合适。QUIC解决了上面的歧义。与SequenceNumber不同,PacketNumber是严格单调递增的。如果PacketN丢失了,重传时Packet的标识不会是N,而是一个比N大的数,比如N+M,这样发送方在收到确认消息的时候,方便知道ACK是否对应到原始请求或重传请求。1.6.4ACK延迟TCP在计算RTT时,没有考虑接收方收到数据到发送确认消息之间的延迟。如下图所示,这个延时就是ACKDelay。QUIC将这种延迟考虑在内,使RTT计算更加准确。1.6.5更多ACK块一般来说,接收方在收到发送方的报文后应该发送一个ACK回复,表示数据已经收到。但是每收到一条数据都要返回ACK回复太麻烦了,所以一般不会马上回复,而是收到多个数据后才回复。TCPSACK最多提供3个ACK??块。但是在某些场景下,比如下载,服务器只需要返回数据,但是按照TCP的设计,每收到3个数据包就必须“礼貌”的返回一个ACK。并且QUIC最多可以携带256个ACK??块。在丢包率比较严重的网络中,增加ACK块可以减少重传量,提高网络效率。1.7流量控制TCP会控制每个TCP连接的流量。流量控制就是发送端不能发送太快,接收端要有时间接收,否则会造成数据溢出和丢失。TCP流量控制主要是通过滑动窗口来实现的。可见,拥塞控制主要控制发送方的发送策略,而没有考虑接收方的接收能力。流量控制是对这部分能力的补充。QUIC只需要建立一个连接,同时在这个连接上传输多个Streams,就好比有一条路,两端都是仓库,路上有很多车辆在运送物资。QUIC的流控有两个层次:ConnectionLevel和StreamLevel。就像控制这条路的总流量一样。不要让大量车辆一下子涌进来,货物得不到及时处理。车辆一次运输大量货物,货物来不及处理。QUIC是如何实现流控的?我们先来看单个Stream的流控。当Stream还没有传输数据时,接收窗口(flowcontrolreceivewindow)为最大接收窗口(flowcontrolreceivewindow)。随着接收方接收数据,接收窗口不断缩小。在接收到的数据中,有的数据已经处理完毕,有的数据还没有来得及处理。如下图,蓝色方块代表处理后的数据,黄色方块代表未处理的数据。这部分数据的到来使得Stream的接收窗口缩小。随着数据继续被处理,接收方有能力处理更多的数据。当(flowcontrolreceiveoffset-consumedbytes)<(maxreceivewindow/2)满足时,接收方将发送一个WINDOW_UPDATE帧,告诉发送方你可以发送更多数据。此时流控接收偏移量会发生偏移,接收窗口会增大,发送方可以向接收方发送更多的数据。Stream级别对于防止接收端接收过多数据作用有限,更有必要使用Connection级别的流控。理解了Stream流量之后,也就很容易理解Connection流控了。在Stream中,流控接收窗口(flowcontrolreceivewindow)=最大接收窗口(maxreceivewindow)-接收数据(最高接收字节偏移量),而对于Connection:接收窗口=Stream1接收窗口+Stream2接收窗口+..。+StreamN接收窗口。2.总结QUIC丢掉了TCP和TLS的包袱,基于UDP,借鉴并改进了TCP、TLS、HTTP/2的经验,实现了一个安全、高效、可靠的HTTP通信协议。凭借0RTT建立连接、平滑连接迁移、基本消除队头阻塞、改进拥塞控制和流量控制等优良特性,QUIC在大多数场景下都取得了比HTTP/2更好的效果。一周前,微软宣布开源自己的内部QUIC库MsQuic,并将全力推荐QUIC协议替代TCP/IP协议。HTTP/3前景广阔。