赞
踩
QUIC(Quick UDP Internet Connections)即 快速UDP网络连接,是由Google开发的基于UDP的传输层网络协议。QUIC的设计目标是提高网络应用程序的性能和可靠性,特别是在高延迟和不稳定网络环境下。
quic文档地址:https://quicwg.org/base-drafts/rfc9000.html
quic架构图:
新的传输层协议通常会经过严格的设计,分析和评估可重复的结果,证明候选协议对 现有协议的正确性和公平性,开发新的传输层协议和它在操作系统进行广泛部署之间 通常需要花费数年的时间。
再者,用户与服务器之间要经过许多防火墙、NAT(地址转换)、路由器和其他中间设 备,这些设备很多只认TCP和UDP。如果使用另一种传输层协议,那么就会有可能无法 建立连接或者报文无法转发,这些中间设备会认为除TCP和UDP协议以外的协议都是不 安全或者有问题的。
● QUIC连接:Client和Server之间的通信关心,Client发起连接,Server接受连接
● 流(Stream):一个QUIC连接内,单向或者双向的有序字节流。一个QUIC连 接可以同时包含多个Stream
● 帧(Frame):QUIC连接内的最小通信单元。一个QUIC数据包(packet)中的 数据部分包含一个或多个帧
ORTT 指的是“Operation Round-Trip Time”(操作往返时间)。这通常是指在计算机网络中,一个数据包从发送端发出,到达接收端并得到响应,然后返回到发送端所需的总时间。这是一个关键的性能指标,因为它可以反映网络的延迟和响应能力。
ORTT的关键点包括:
如何测量ORTT:
优化ORTT的方法:
理解和优化ORTT对于提高网络应用的性能和用户体验至关重要。
一个 QUIC 数据包的格式
● Header 是明文的,包含 4 个字段:Flags、Connection ID、QUIC Version、Packet Number;
● Data 是加密的,可以包含 1 个或多个 frame,每个 frame 又分为 type 和 payload, 其中 payload 就是应用数据
数据帧有很多类型:Stream、ACK、Padding、Window_Update、Blocked 等,这里重点介 绍下用于传输应用数据的 Stream 帧。
Frame Type: 帧类型,占用 1 个字节
(1)Bit7:必须设置为 1,表示 Stream 帧,一个udp通道可以发送多个流
(2)Bit6:如果设置为 1,表示发送端在这个 stream 上已经结束发送数据,流将处于半关闭状态
(3)Bit5:如果设置为 1,表示 Stream 头中包含 Data length 字段
(4)Bit432:表示 offset 的长度。000 表示 0 字节,001 表示 2 字节,010 表示 3 字节,以此类推
(5)Bit10:表示 Stream ID 的长度。00 表示 1 字节,01 表示 2 字节,10 表示 3 字节,11 表示 4 字 节
Stream ID:流 ID,用于标识数据包所属的流。后面的流量控制和多路复用会涉及到。
Offset:偏移量,表示该数据包在整个数据中的偏移量,用于数据排序。
Data Length: 数据长度,占用 2 个字节,表示实际应用数据的长度 Data: 实际的应用数据。
典型TCP+TLS连接
1.首先,执行三次握手,建立 TCP 连接(蓝色部分);
2.然后,执行 TLS 握手,建立 TLS 连接(黄色部分);
3.此后开始传输业务数据;
客户端和服务器之间要进行多轮协议交互,才能建立 TLS 连接,延迟相当严重。 平时访问 https 网站明显比 http 网站慢,三次握手和 TLS 握手难辞其咎。
QUIC首次连接
● 共3RTT:TCP+TLS1.2中: TCP三次握手建立连接需要1个RTT;TLS需要2个RTT完成 身份验证;传输数据
● 共2RTT:TCP+TLS1.3中: TCP三次握手建立连接需要1个RTT;TLS需要1个RTT完成 身份验证;传输数据
● 共1RTT: 首次QUIC连接中,Client 向 Server 发送消息,请求传输配置参数和加 密相关参数;Server 回复其配置参数;传输数据
注解:
注意到,三次握手中的 ACK 包与 handshake 合并在一起发送。 这是 TCP 实现中使用的 延迟确认 技术, 旨在减少协议开销,改善网络性能。
QUIC再次连接
● 再次连接的概念:Client已经访问过Server,在本地存放了Cookie。
● 2RTT:TCP+TLS1.2中: TCP三次握手建立连接需要1个RTT;TLS需要1个RTT完成身份 验证(由于缓存的存在,减少1RTT);传输数据
● 1RTT:TCP+TLS1.3 中: TCP三次握手建立连接需要1个RTT;传输数据
● 0RTT:在客户端与服务端的再次QUIC连接中,Client 本地已有 Server 的全部配置 参数(缓存),据此计算出初始密钥,直接发送加密的数据包。
在一个网页里面总是会有多个数据要传输,总是希望多个数据能够同时传输,以此 来提高用户的体验。
在HTTP1.1中:
● 每个TCP连接同时只能处理一个请求—响应,为了提高响应速度,需要 同时创建多个连接,但是多个连接管理比较复杂
在HTTP2中:
● 每个TCP连接里面有多个逻辑上独立的多个流(stream)
● 每个流可以传输不同的文件数据
● 解决了HTTP1一个连接无法同时传输多个数据的问题
● 缺点:容易出现队头阻塞问题
而在基于QUIC的HTTP3中:
● 借鉴了HTTP2中流的概念
● 流 之 间 互 相 独 立 , 即 不 同 流 之 间 的 数 据 之 间 交 付 顺 序 无 关 ( 如果 stream2的数据丢失,只会影响排在stream2后面的数据,stream1和 stream3的数据不会被影响)
● 建立在UDP之上,没有依赖性
HTTP/2会出现队头阻塞问题,而在基于QUIC的HTTP/3中则很好地解决这一问题.
UDP中的各个数据报独立,基于UDP的QUIC中的各个stream独立
即使stream2里有一个包丢失,因为stream之间互相独立无关联,所以不会 阻塞stream3、stream4,依然可以交付给上层
TCP 的拥塞控制实际上包含了四个算法:慢启动,拥塞避免,快速重传,快 速恢复
(1)New Reno:基于丢包检测
(2)CUBIC:基于丢包检测
(3)BBR:基于网络带宽 可以自己去设置拥塞控制机制,也可以自己去实现拥 塞控制协议
QUIC 协议当前默认使用了 TCP 协议的 Cubic 拥塞控制算法。
这个机制还是可插拔的,什么叫可插拔呢?就是能够非常灵活地生效,变 更和停止,可以根据场景来切换不同的方法。
QUIC协议在用户空间实现,应用程序不需要停机和升级就能实现拥塞控制 的变更,在服务端只需要修改一下配置,reload 一下,完全不需要停止服务 就能实现拥塞控制的切换。甚至可以为每一个请求都设置一种拥塞控制算法。
而TCP在内核态,其拥塞控制难以进行修改和升级。
场景:
连接迁移:当客户端切换网络时,和服务器的连接并不会断开,仍然可以正常通信, 对于 TCP 协议而言,这是不可能做到的。因为 TCP 的连接基于 4 元组:源 IP、源端口、 目的 IP、目的端口,只要其中 1 个发生变化,就需要重新建立连接。但 QUIC 的连接是 基于 64 位的 Connection ID,网络切换并不会影响 Connection ID 的变化,连接在逻辑上 仍然是通的。
IP地址或者端口号发生变化时,只要ID不变,依然能够维持原有连接,上层业务逻辑感 知不到变化,不会中断。
假设客户端先使用 IP1 发送了 1 和 2 数据包,之后切换网络,IP 变更为 IP2,发送了 3 和 4 数据包,服务器根据数据包头部的 Connection ID 字段可以判断这 4 个包是来自于同一 个客户端。QUIC 能实现连接迁移的根本原因是底层使用 UDP 协议就是面向无连接的。
相比于TCP,QUIC的安全性是内置的,也就是说是必须的。
在恶意环境下性能与TLS类似,友好环境下优于TLS,因为TLS使用一个会话密钥, 如果这个密钥被截获的话就不能保证之前数据的安全性。
而QUIC使用两个密钥——初始密钥和会话密钥,并且QUIC提供密码保护,TLS不提供。
除此之外,QUIC的包头经过身份认证,包内数据是加密的。这样如果QUIC数据 被恶意修改的话接收端是可以发现的,降低了安全风险。
而且数据加密之后,可以通过像防火墙或者nat这些中间件。
FEC是Forward Error Correction前向错误纠正的意思,就是通过多发一些冗余的包, 当有些包丢失时,可以通过冗余的包恢复出来,而不用重传。这个算法在多媒 体网关拥塞控制有重要的地位。QUIC的FEC是使用的XOR的方式,即发N + 1个包, 多发一个冗余的包,在正常数据的N个包里面任意一个包丢了,可以通过这个冗 余的包恢复出来,使用异或可以做到切换网络操持连接。
1 2 3 4,重新编码 出来 5 4 3 2 1 -> 5 4 3 2 -> 4 3 2 1
QUIC 是基于 UDP 协议的,而 UDP 是不可靠传输协议,那 QUIC 是如何实现可靠传输的呢? 可靠传输有 2 个重要特点:
(1)完整性:发送端发出的数据包,接收端都能收到
(2)有序性:接收端能按序组装数据包,解码得到有效的数据
解决方案:通过包号(PKN)和确认应答(SACK)
(1)客户端:发送 3 个数据包给服务器(PKN = 1, 2,3)
(2)服务器:通过 SACK 告知客户端已经收到了 1 和 3,没有收到 2
(3)客户端:重传第 2 个数据包(PKN=4) 由此可以看出,QUIC 的数据包号是单调递增的。 也就是说,之前发送的数据包(PKN=2)和重传的 数据包(PKN=4),虽然数据一样,但包号不同。
解决方案:通过数据偏移量 offset
每个数据包都有一个 offset 字段,表示在整个数据中的偏移量。
接收端根据 offset 字段就可以对异步到达的数据包进行排 序了。为什么 QUIC 要将 PKN 设计为单调递增?解决 TCP 的重传歧义问题:
由于原始包和重传包的序列号是一样的,客户端不知道服 务器返回的 ACK 包到底是原始包的,还是重传包的。但 QUIC 的原始包和重传包的序列号是不同的,也就可以判 断 ACK 包的归属。
QUIC协议对带宽使用进行了优化,通过更高效的ACK机制和流控算法,减少了不必要的数据传输和重复确认。
QUIC最初由Google在其自家服务中使用,并且已经成为HTTP/3的基础。HTTP/3是HTTP协议的最新版本,旨在利用QUIC的优势来提高网页加载速度和用户体验。
QUIC协议已经得到了广泛的支持和应用,许多现代浏览器(如Google Chrome、Mozilla Firefox)和服务器(如NGINX)都已经实现了对QUIC的支持。
QUIC协议通过结合UDP的低延迟和TCP的可靠性,为现代互联网应用提供了一种高效、安全的传输方案。
ngtcp2 仓库 https://github.com/ngtcp2/ngtcp2,ngtcp2采用c语言实现,范例client和server使用了c++17的特性,我们需要升级编译器(比如, clang >= 8.0, 或 gcc >= 8.0).
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。