掘金地址:https://juejin.cn/post/7428200842229006377
引言
QUIC是什么?明明你每天都在用,明明每天都在timing,难道你不知道吗?啊?不会吧,不会吧。
那就让本文来让你全方位的了解这个协议。
一、QUIC是什么
QUIC协议的提出有其背景原因。随着网络技术的不断进步和发展,人们的在线娱乐需求也在逐渐升级。从前,人们或许满足于观看预先录制好的视频片段。但现在,用户们不再满足于此,他们渴望体验到更加即时且互动性更强的直播形式。
然而,传统的TCP协议因存在头部阻塞问题和慢启动问题,难以实现这种低延迟传输的要求。在这种背景下,谷歌公司作为这种好心人,为了满足这种需求,推出了QUIC(Quick UDP Internet Connections,快速UDP互联网连接)这一全新协议。
尽管QUIC看似是一种在应用层实现的协议,但实际上它提供的是传输层的功能。那么,QUIC究竟属于哪一层呢?
我们从维基百科可以看到是一种传输层协议:
那有读者疑问就来了,干嘛整这么复杂呢???传输层就传输层,应用层就应用层,干嘛来一个不伦不类的基于应用层实现的传输层协议?
其实也是有苦衷的:
-
传输层协议实现过于复杂
-
协议的话,写入的都是在操作系统内核中,如果新增了一个协议,需要对全世界所有系统都进行重装,那可真是更麻烦了
看到这里,我只能说:
二、QUIC 核心功能
在开始之前,我们先来一幅图,让我们对比Http1.1、Http/2、QUIC三者之间的区别:
从图中,我们可以看出,没看出也没事,但是我们知道的是QUIC的设计也是参照了Http/2实现的。实现的功能我们先列举出来:
-
快速握手和连接迁移
-
自适应流控和多路复用Stream
-
错误重传
-
拥塞控制
-
安全性
接下来,我们一一来说:
2.0、头部设计
要基于 UDP 实现的可靠传输协议,那只能要设计好协议的头部字段。拿 HTTP/3 举例子,在 UDP 报文头部与 HTTP 消息之间,共有 3 层头部:
-
QUIC packet(包)头部:建立连接;
-
QUIC frame(帧)头部:进行传输;
-
Http/3 帧头部:与HTTP头部有关联,不关传输的事
这里有个印象即可,等下会针对重要头部信息进行细说。
2.1、连接建立
2.1.1、快速握手
对于HTTP/1和HTTP/2协议,HTTPS的加密是分层实现的:
-
TCP三次握手(1RTT)
-
TLS四次握手(2RTT)
这意味着,通常需要3个RTT(往返时间)才能开始传输数据。即使使用Session会话复用,也需要至少2个RTT。
而对于HTTP/3(使用QUIC),情况有所不同:
-
首次连接:QUIC内部集成了TLS,使用TLS 1.3协议,仅需1个RTT即可完成连接建立与密钥协商。
-
复用连接:第二次连接复用时,应用数据与QUIC握手信息一起发送,实现0-RTT的效果。
细谈谈连接过程:(这部分了解即可,其实就是建立连接与TLS连接融合在一起了)
客户端发起连接:客户端发送一个初始的QUIC数据包
初始数据包头部:该头部包含一个随机生成的连接ID,用于标识这条QUIC连接。
TLS ClientHello 消息:QUIC结合了TLS 1.3的握手机制,客户端首先发送TLS ClientHello消息,包含其加密参数和其他握手所需信息。
由于QUIC使用的是UDP协议,所以不需要像TCP那样的三次握手过程,客户端在发送第一个数据包时就可以携带应用层数据,降低了连接的延迟。
服务器响应:服务器接收到客户端的初始包后,进行如下操作:
验证客户端的初始包:服务器检查客户端的连接ID和相关信息。
返回TLS ServerHello 消息:服务器返回自己的加密参数,并确认TLS握手的信息。如果需要,服务器可能还会返回一个Token来进行客户端验证(防止DoS攻击)。
携带加密确认的消息:服务器返回的ServerHello消息中携带了加密确认和部分握手信息,这意味着部分加密已经完成。
此时,QUIC连接尚未完全建立,仍处于握手阶段,但加密通道已经部分建立,后续的数据包可以通过加密的方式传输。
客户端确认:客户端收到服务器的ServerHello消息后,完成剩余的TLS 1.3握手流程:
客户端完成握手:客户端基于服务器的加密参数,生成并发送一条消息来确认加密通道的建立。
交换应用数据:完成握手后,客户端和服务器可以开始传输应用层数据。
在这个阶段,QUIC连接就完全建立,双方可以在加密的情况下传输数据。
https://zhuanlan.zhihu.com/p/301505712
2.1.2、连接迁移
讨论完初始连接后,让我们转向QUIC连接复用的话题:
在复用已有连接时,QUIC能够实现0-RTT(零往返时间),这是因为复用基于之前握手过程中协商得出的连接ID来实现。这一机制不仅简化了后续交互的过程,还极大地提高了效率。
想象一下你在玩一个在线游戏,从家里的Wi-Fi网络切换到外面的4G网络。如果使用传统的TCP协议,这种切换可能会导致游戏卡顿或断线。但在QUIC协议下,情况完全不同:
当你在家用Wi-Fi玩游戏时,QUIC会为你的连接分配一个唯一的连接ID。当你离开家,手机自动切换到4G网络时,QUIC会使用同一个连接ID来标识连接。这样一来,即使网络变了,游戏仍然可以无缝继续,不会有任何中断或延迟。
这种设计确保了QUIC协议下的通信能够在不同的网络环境下平滑过渡,提供更好的用户体验。
2.1.3、连接原理解析 —— QUIC packet(包)头部
要理解QUIC协议如何建立连接,首先需要解析用于建立连接的QUIC包头(Packet Header)结构:
QUIC包头可以细分为两种类型:
-
长包头(Long Packet Header):用于初始连接的建立;
-
短包头(Short Packet Header):用于常规的数据传输。
QUIC使用三次握手来建立连接,其主要目标是为了协商连接ID。一旦协商出了连接ID,后续的传输过程中,双方只需要维持该连接ID不变,这样就可以支持连接迁移的功能。因此,在常规数据传输中使用的短包头中,不再需要包含源连接ID字段,而只需要包含目的连接ID。
短包头中的包编号(Packet Number)
是每个报文唯一的标识符,并且它是严格递增的。这意味着即使某个特定的包(如Packet N)丢失并需要重传,重传的包的编号也不会再是N,而是一个大于N的数值。
2.2、数据传输
2.2.0、QUIC Frame Header
QUIC的数据传输是在QUIC Frame Header中进行的;一个Packet报文中可以存放多个QUIC Frame。先来看看它的整体结构:
-
Stream ID:用于区分多个并发传输的HTTP消息,类似于HTTP/2中的Stream ID。
-
Offset:类似于TCP协议中的Seq序号,保证数据的顺序性和可靠性。
-
Length:指明Frame数据的长度。
通过引入Frame Header,Stream ID + Offset 字段信息实现数据的有序性。通过比较两个数据包的Stream ID与Offset,如果都一致,说明这两个数据包的内容一致。
2.2.1 、自适应流控
首先,我们来回顾一下TCP的流量控制是如何实现的。
TCP的流量控制机制是基于接收方告知发送方其当前接收窗口大小的原理,从而使发送方能够根据接收方的实际接收能力调整其发送速率。这就好比在学校食堂打饭时,为了不浪费食物,学生会根据自己的食量告诉打饭的阿姨要多少份量的食物。同样,在TCP中,接收方会定期向发送方报告其缓冲区还有多少空间可供使用,发送方则据此调整其发送的数据量。
而在QUIC协议中,流量控制机制更加精细且层次分明:
-
Stream级别的流量控制:在QUIC协议中,每个Stream(可以理解为一条HTTP请求)都有其独立的滑动窗口机制来进行流量控制。这样可以确保任何一个Stream不会独占整个连接的接收缓冲区,从而避免因单个Stream的数据量过大而导致的缓冲区溢出。
-
Connection级别的流量控制:QUIC不仅提供了Stream级别的流量控制,还实现了Connection级别的流量控制,即对连接中的所有Stream所发送的数据总量进行限制,防止发送方的数据总量超出接收方的缓冲区容量。
总的来说,QUIC的流量控制机制不仅细化到了单个流级别,还从整体连接的角度进行了把控,从而提供了比TCP更灵活且高效的传输性能。
流控这块,如果希望详细了解的话,可以看这篇文章:https://juejin.cn/post/7066993430102016037#heading-5
2.2.2、 多路复用Stream
QUIC实现的多路复用Stream我只能说跟Http/2太像了,都是基于Stream实现的并发传输,但是呢?Http/2有一个大 Problem——队头阻塞(即一个Stream中包丢失,则阻塞全部请求),因为它始终复用的只是一个TCP面向连接的传输信道,但是QUIC可不一样,是基于UDP实现的无连接传输,所以在多路复用Stream的时候才算是真真正正的实现无干扰的多路复用Stream,显著提升了网络传输的效率和响应速度
2.3 、错误重传
2.3.1、定时器和ACK/NACK机制
QUIC通过定时器和ACK/NACK机制来检测丢包并进行重传。接收方定期发送ACK报文告知已接收的数据包。若数据包丢失,接收方不发送ACK,发送方通过定时器检测并在超时后重传。此机制类似TCP,但更灵活高效。
2.3.2、前向纠错(FEC)
QUIC利用FEC技术减少重传次数。发送端编码原始数据并添加冗余信息,接收端用这些信息恢复丢失的数据包。例如,海明码通过冗余位进行错误校验和纠正。
2.4、拥塞控制
QUIC的拥塞控制机制非常类似于TCP,但更加灵活和智能。它使用了类似TCP的拥塞控制算法,比如CUBIC(慢开始、拥塞避免、快重传、快恢复策略),来调节发送速率并避免网络拥塞。拥塞控制的核心思想是根据网络拥塞的程度调整发送数据的速度,以最大限度利用带宽,同时避免过度负载。
与TCP不同的是,QUIC可以利用自己的流控和拥塞控制机制在多个独立的数据流上并发应用这些控制策略,使得网络资源的利用更加高效,特别是在高延迟或高丢包率的网络环境中。
2.5、总结优势
综上所述,QUIC对比与Http/2最大的亮点主要体现在以下三个方面:
-
无队头阻塞:QUIC通过独立的数据流设计,避免了由于单个数据包丢失而导致整个连接阻塞的问题,从而提高了传输效率。
-
更快的连接建立:QUIC优化了连接建立过程,减少了握手延迟,使得客户端与服务器之间的连接建立速度更快。
-
连接迁移:QUIC支持无缝的连接迁移,允许客户端在不中断现有连接的情况下改变其IP地址或端口,这对于移动设备在网络切换时保持持续连接尤其重要。
这三点优化使得QUIC在具备与TCP类似的流控和拥塞控制功能的同时,具有更大的优势。
再谈谈一些实际的测试用例吧,这里以网易的弱网环境测试为例:https://juejin.cn/post/7091478561613152269?searchId=202410201416118B99FD352B15EF1724DB#heading-4
发现明显的会比TCP相应快个几百ms,这对系统性能还是优化挺大的。
三、面临的挑战
-
路由器和防火墙限制:一些网络设备可能限制或封堵UDP流量,尤其是443端口上的UDP流量,这是QUIC常用的端口。这可能导致QUIC流量被意外拦截或丢弃。
-
QoS(Quality of Service)问题:由于QUIC使用UDP,某些网络服务提供商可能会误认为大量的UDP流量是潜在的DDoS攻击,并采取措施限制或丢弃这些流量。
-
部署难度: 目前 QUIC 的部署相对较为复杂,需要网络和服务器端的双方都支持。
-
协议升级: QUIC 协议仍在不断发展,升级过程中可能会涉及到版本兼容性的问题。
-
caniuse?
四、应用与启动
4.1、应用场景
应用场景:
-
HTTP3:弱网环境也可流畅访问
-
低延迟直播:延迟从2s到200ms
-
更多领域:真正即时通讯、网络游戏、物联网
4.2、如何在浏览器中启动
-
火狐浏览器
-
访问:
about:config
-
启用:
network.http.http3.enabled
-
-
Chrome 浏览器
-
访问:
chrome://flags
-
启用:
enable-quic
-
-
测试是否已经支持 QUIC:
-
测试网站: https://quic.nginx.org/
-
HTTP Indicator插件
-
也可以这么来测试:根据F12,查看网络,然后打开协议,我们可以看到其实现在浏览器主流使用的还是Http/2,少部分网站中使用的CDN采用的是Http/3
五、总结
QUIC(Quick UDP Internet Connections)是由谷歌推出的新型传输层协议,旨在提供低延迟的可靠传输服务。通过实现下面三个核心功能:
-
快速握手:仅需1个RTT即可完成连接建立。
-
连接迁移:支持无缝的连接迁移。
-
多路复用:无队头阻塞,多个Stream并发传输。
取得了代替TCP连接,成为Http/3底层使用的传输协议。
参考文章:
-
https://zhuanlan.zhihu.com/p/32553477
-
4.17 如何基于 UDP 协议实现可靠传输? | 小林coding
-
https://juejin.cn/post/7066993430102016037#heading-21