QUIC协议----简单学习整理

引言

2022年6月,HTTP/3正式被标准化为RFC 9114,其将是HTTP超文本传输协议的第三个主要版本。HTTP协议作为一个简单的请求-响应协议,各个主要版本主要是在于优化传输效率及安全性方面进行优化改进。

目前来说,仍存在大量服务器使用HTTP/1.1协议,其特点是,每个请求会独立建立一个TCP连接,而浏览器通常都会对单个域名的连接数进行限制,当连接数量过多,后续的请求就会排队等待。实际中,某些网站会采用多域名的方式去规避上述问题,但每一个请求的TCP建连开销仍然存在。

HTTP/2 采用多路复用技术,解决上述问题,其在一个TCP连接上同时传输多个请求和相应消息,如此排队等待的问题就迎刃而解了,同时也减少了TCP连接过程。除了多路复用提高请求的并发能力之外,还支持服务端主动推送以及头部压缩。其优点很多,但仍存在固有问题,和HTTP/1.1一样,其传输层基于TCP协议,由于TCP协议的丢包重传机制,如果一个请求发生丢包,浏览器会不断重传该数据包,进而阻塞后续请求,这也就是TCP的队头阻塞问题。

HTTP/3采用QUIC协议代替TCP协议提供可靠性传输,QUIC协议是基于UDP协议的,并采用了流的概念,不同的请求通过不同的有序字节流传输,即同一连接下互不影响的逻辑信道。同时具有流ID和流偏移2个字段,使得数据包可以乱序传输,而正确组装。当出现丢包时,仅重传出现丢包的流即可,并不会阻塞其他请求的传输,也就没有队头阻塞的问题。

QUIC

QUIC 源于Quick UDP Internet Connections,而如今是一个独立协议名称。QUIC 是一种基于UDP的安全、可靠、多路复用的传输协议。QUIC 是一种面向连接的协议,它在客户端和服务器之间创建有状态的交互。

QUIC的握手过程包含了加密和传输参数的协商,其集成了TLS握手。握手过程会尽快地完成数据交换,在有前置通信或配置的情况下,可以做到立即发送数据(0-RTT)。QUIC通信是基于数据包的,大多数数据包中含有1个或者更多的帧,这些帧携带控制信息或用户数据,最后利用UDP在网络中传输。上层应用在使用QUIC连接中的有序字节流交换数据,其可以创建两种流:双向流,允许两端均发送数据;单向流,仅允许单个端发送数据。QUIC 连接并不严格绑定到单个网络路径。 连接迁移使用连接标识符(不同于传统的五元组,使用64位随机数作为标识)完成连接转移到新的网络路径。 只有客户端才能在目前版本的 QUIC 中迁移。 还允许在网络拓扑或地址映射发生变化后继续连接,例如可能由 NAT 重新绑定引起的变化。

在这里插入图片描述

QUIC = TLS + TCP+HTTP/2 其整合了TCP的可靠性,TLS的安全性以及HTTP/2多路复用的并发性。

数据格式

Packet

long packet header

Long Header Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2),
  Type-Specific Bits (4),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Type-Specific Payload (..),
}

long packet header 用于在 1-RTT 密钥建立之前发送的数据包。当1-RTT 密钥建立后,发送方会切换回short packet header。long packet header格式被用于特殊的数据包,例如版本协商数据包,其个字段含义如下:

Header Form: 对于long packet header第一个字节的最高位必须设置为1。

Fixed Bit:只有版本协商数据包该位会置为0,但目前未被使用,该位为0的数据包目前不会被处理,设置为1

Long Packet Type: 第一个字节的接下来2位表示数据包的类型,0为Initial Packet,1为0-RTT,2为Handshake Packet,3为Retry Packet,详细内容见最下方RFC文档

Type-Specific Bits: 第一个字节的低四位语义有数据包类型决定。

Version: QUIC 版本是跟在第一个字节之后的 32 位字段。 此字段指示正在使用的 QUIC 版本,并确定如何解释其余协议字段。

Destination Connection ID Length: 版本后面的字节包含其后面的目标连接 ID 字段的字节长度。8位无符号整数

Destination Connection ID: 连接标识ID

Source Connection ID Length: 源连接 ID 字段的字节长度。 8 位无符号整数。

Source Connection ID:源连接ID

Type-Specific Payload: 数据包的其余部分(如果有)是特定于类型的。


short packet header

Packet {
  Header Form (1) ,
  Fixed Bit (1) ,
  Spin Bit (1),
  Reserved Bits (2),
  Key Phase (1),
  Packet Number Length (2),
  Destination Connection ID (0..160),
  Packet Number (8..32),
  Packet Payload (8..),
}

1-RTT 数据包使用short packet header。 它在版本协商和 1-RTT 密钥协商后使用。

Header Form: 对于short packet header,第一个字节的最高位设置为0。

Fixed Bit: 只有版本协商数据包该位会置为0,但目前未被使用,该位为0的数据包目前不会被处理,设置为1。

Spin Bit:第一个字节 的第三个最高有效位表示延迟自旋位。

Reserved Bits: 下两位被保留。

Key Phase: 下一位表示密钥阶段,它允许数据包的接收者识别用于保护数据包的数据包保护密钥。

Packet Number Length: 最低有效两位包含数据包编号字段的长度,编码为无符号两位整数,比数据包编号字段的长度(以字节为单位)小 1。 即 Packet Number 字段的长度是该字段的值加一。

Destination Connection ID: 连接标识ID

Packet Number:字段的长度为 1 到 4 个字节。 数据包编号使用Header protection进行加密。

Packet Payload:1-RTT 数据包总是包含一个 1-RTT 加密的有效载荷。

Frame

Packet (负载部分)包含一个或多个Frame。Frame的类型由很多,如PADDING Frames、PING Frames、ACK Frames 、RESET_STREAM Frames、STOP_SENDING Frames、CRYPTO Frames、STREAM Frames、CONNECTION_CLOSE Frames、HANDSHAKE_DONE Frames等等。

Frame {
  Type (i) ,
  [Type-Specific Payload],
}

Type: 表示帧的类型。

QUIC Stream数据流是QUIC主要数据传输的载体,STREAM Frames是其必要组成单元,以此为例简单介绍。

STREAM Frame {
  Type (i) = 0x08..0x0f,
  Stream ID (i),
  [Offset (i)],
  [Length (i)],
  Stream Data (..),
}

Stream ID: 一个可变长度整数,表示流的流 ID。原版协议支出是一个62位的整数,一般认为1-4个字节长度

Offset: 一个可变长度整数,指定此 STREAM 帧中的数据在流中的字节偏移量。一般认为0-8个字节长度

Length: 一个可变长度整数,指定此 STREAM 帧中流数据字段的长度。一般认为0-2个字节长度

Stream Data: 被传递的指定流中的数据。

更详细的说明:https://zhuanlan.zhihu.com/p/405387352

握手

QUIC实现了快速握手,并把握手过程分为两种情况,分别是1-RTT和0-RTT。

在这里插入图片描述

1-RTT建连

若客户端没有服务器相关配置信息,只能进行1-RTT建连。

  1. 客户端主动向服务器发起连接,发送Inchoate CHLO 请求服务器配置参数。
  2. 服务器收到CHLO后,回复REJ(rejection)消息,其中含有服务器配置参数。
  3. 客户端向服务器发送complete CHLO消息,携带其生成的公开数,此时客户端已经可以根据服务端配置信息和自身选择的随机数,计算出初始密钥。
  4. 服务器收到complete CHLO消息,利用客户端的公开数计算出初始密钥,并向客户端回复用初始密钥加密的的SHLO消息,其含有一个服务器生成的临时随机数,用于生成会话密钥。
  5. 客户端收到SHLO消息,并用初始密钥解密,进而生成会话密钥。
  6. 客户端和服务器之前,利用会话密钥进行加密通信。

QUIC集成了TLS1.3,在协商完初始密钥后即会同时发送业务数据,并在更新会话密钥后切换到使用会话密钥,所有仅有1-RTT时间的延时。

0-RTT

如上所述,如果客户端缓存有服务器配置信息,可以直接发送complete CHLO消息,并发送加密数据。服务器收到消息后,会用初始密钥解密数据,并产生随机数用于生成会话密钥,并回复携带随机数的SHLO消息,客户端利用该随机数生成会话密钥,客户端和服务器之前,利用会话密钥进行加密通信。

在初始密钥后,再协商出一个最终的会话密钥,其目的是为了获取前向安全特性,服务端的后面生成的这份公私钥是临时生成的,不会保存下来,也就杜绝了密钥泄漏导致会话数据被恶意收集后的被解密的风险。

QUIC性能特点

建连更快

QUIC建连时间大约0~1 RTT,在两方面做了优化,一是传输层使用了UDP,相比于TCP减少了1RTT的三次握手的建连时间。二是加密协议采用了TLS 协议的最新版本TLS 1.3,相对之前的TLS 1.1-1.2,TLS1.3允许客户端无需等待TLS握手完成就开始发送应用程序数据,可以支持0-RTT和 1-RTT。

对于QUIC协议,客户端第一次建连的握手协商需1-RTT,而已建连的客户端重新建连可以使用之前协商好的缓存信息来恢复TLS连接,仅需0-RTT时间。因此QUIC建连时间大部分0-RTT、极少部分1-RTT,相比HTTPS的3-RTT的建连,具有极大的优势。

避免队头阻塞的多路复用

QUIC也支持多路复用,相比HTTP/2,QUIC的流与流之间完全隔离的,互相没有时序依赖。如果某个流出现丢包,仅重传丢包的流即可,不会阻塞其他流数据的传输和应用层处理,所以其并不会造成队头阻塞。

连接迁移

任何一条 QUIC 连接不再五元组作为标识,而是以一个 64 位的随机数作为 ID 来标识,这样就算 IP 或者端口发生变化时,只要 ID 不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。由于这个 ID 是客户端随机产生的,并且长度有 64 位,所以冲突概率非常低。

可选的拥塞控制算法

Cubic、BBR、Reno等拥塞控制算法,也可以根据具体的场景定制私有算法。

两级流量控制

QUIC同样采用了滑动窗口机制,在Connection和Stream两个级别分别进行流量控制。 用公式表示就是: connection可用窗口 = stream1可用窗口 + stream2可用窗口 + streamN可用窗口

前向纠错(FEC)

QUIC支持前向纠错,通过增加冗余数据,使数据包具有自动纠错的能力,可以减少重传次数,提升传输效率。

QUIC发展的一些问题

摘选自https://mp.weixin.qq.com/s/Ogfj0QlLF17sD60L3pwYXw

集成难度

无论是在客户端还是服务端,QUIC协议的集成并非一件易事。如果当前使用的网络不支持QUIC,意味着我们需要修改应用程序来适配网络库的调整。这往往并不是应用迭代的出发点。

下面让我们来看看客户端和服务端在集成QUIC协议时需要考虑的问题:

客户端

  • 应用适配成本和收益之间的权衡。
  • 过渡期可能还需要新旧网络库都存在,方便降级容错,增加应用体积。
  • 不同的QUIC库的接口并不统一,不像Socket统一接口具备移植性。

服务端

  • 网络事件模型需要适配QUIC协议栈做调整,同时还要考虑和TCP的兼容。
  • 后端架构面临调整,4层Load Balancer是否支持QUIC,HTTP/3的QUIC流量如何换成HTTP/1转给Backend Service。
  • 需要考虑到多Region、多节点之间的QUIC连接复用和连接迁移。
  • 服务端QUIC流量的能耗比,如何做到和TCP一样的能耗性能。

QUIC协议栈性能

对比已经发展了三十多年的TCP协议,新兴的QUIC协议在协议栈实现的工程上还有很多优化的事情要做,根据Google 2017年公开的数据,当时QUIC同等流量的CPU消耗是TCP的2倍之多。QUIC协议栈的性能痛点主要有:

  • UDP数据包收发性能
  • 数据装包、拆包处理性能
  • 数据包解析性能
  • ACK处理性能
  • 加、解密性能
  • 其他流程处理的性能:数据包Pacing、CC算法、内存使用等

UDP数据包性能

UDP数据包在内核接收发送上一直没有得到和TCP数据包一样的优化待遇,UDP收发占据了QUIC协议栈比较大的消耗。

  • 原始的sendto/write的UDP Socket接口性能很弱。
  • 批量收发数据sendmsg/sendmmsg提升不够明显。
  • 内核GRO/GSO可以提升性能,但还不够。
  • 内核XDP或者DPDK可大幅提升性能,但程序改造量极大。
  • 硬件NIC Offload UDP收发能终极优化,同样程序改造量极大。

UDP被运营商QoS限制

国内运营商确实会对UDP流量做些QoS的限制,但是能够被QoS限制的比例微乎其微,可以完全忽略。运营商这么做主要基于两个原因:

  1. UDP流量五元组在NAT状态上连接老化的时间控制不够精确,时间设置太长会破坏低频通信的UDP连接,太短会导致UDP连接消耗比较多的设备性能。一般会选择一个折中的经验值,这就会伤害一些特定场景的UDP流量了。

  2. 运营商设备上包分类的优先级队列对于UDP五元组的管理比较困难,因为UDP的五元组会频繁变动,只能眼睁睁看着UDP流量挤占各级队列,却没办法实施精确地控制。一般来说,运营商会在特定时间段或者特定负载情况下对UDP流量做全局限制。

QUIC Datagram——QUIC的非可靠数据报文传输扩展

QUIC v1(RFC9000)提供了一个安全、可靠、多路复用的传输方案,QUIC Stream数据流是QUIC主要数据传输的载体,可靠传输是其需要保证的基本功能。

但是有些应用场景并不需要严格的可靠传输,例如实时音视频、在线游戏等。现在这些场景有些是直接基于自定义UDP或者WebRTC实现的。自定义UDP实现传输层功能的话比较麻烦,工程量大,有时候为了安全考虑还需要加上DTLS支持,而WebRTC的建立数据传输通道流程也比较繁琐,WebRTC主要场景是为了P2P设计的,长远来看并不适合客户端服务端的场景。

因此,QUIC支持不可靠数据传输能够让QUIC协议的应用范围更广,适合更多的应用场景,而且QUIC之上的不可靠数据传输能够很好地复用QUIC的安全特性。

QUIC Datagram特点

  • 同一QUIC连接里面可以同时包含可靠Stream传输和不可靠数据传输,它们可以共享一次握手信息,分别可以作用于TLS和DTLS,可降低握手延迟。
  • QUIC在握手上比DTLS更加精准,它对每个握手数据包加上了超时重传定时器,能够快速感知握手包的丢失和恢复。
  • QUIC Datagram的不可靠传输也可以被ACK,这是一个选项,如果有ACK,可以让应用程序感知到QUIC Datagram的成功接收。
  • QUIC Datagram也适用于QUIC的CC。

这些特性能够让实时音视频流、在线游戏和实时网络服务等应用的传输得到极大的效率提升。

参考文献

QUIC RFC9000 https://quicwg.org/base-drafts/rfc9000.html

QUIC Datagram: https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram-06

QUIC协议的发展 https://mp.weixin.qq.com/s/Ogfj0QlLF17sD60L3pwYXw

QUIC 是如何解决TCP 性能瓶颈的 https://mp.weixin.qq.com/s/PZ1IbXe396b6gzmWYpFk-Q

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
nginx-quic是nginx的一个版本,它支持QUIC协议QUIC是一种基于UDP的传输协议,旨在提供更快的连接建立和数据传输速度。要获取nginx-quic版本的nginx可执行文件,需要进行一系列的安装和编译步骤。 首先,你可以使用已经编译好的版本nginx-quic.linux-x86_64.zip,下载链接在\[5\]中提供。如果你想自己编译,可以按照以下步骤进行准备工作: 1. 下载nginx源码包:使用curl命令下载nginx源码包,例如: ``` curl -O https://nginx.org/download/nginx-1.16.1.tar.gz ``` 2. 解压源码包:使用tar命令解压下载的源码包,例如: ``` tar xvzf nginx-1.16.1.tar.gz ``` 3. 克隆quiche库:使用git命令克隆quiche库,例如: ``` git clone --recursive https://github.com/cloudflare/quiche ``` 4. 进入nginx源码目录:使用cd命令进入nginx源码目录,例如: ``` cd nginx-1.16.1 ``` 5. 应用补丁:使用patch命令应用quiche提供的补丁,例如: ``` patch -p01 < ../quiche/extras/nginx/nginx-1.16.patch ``` 6. 配置编译选项:使用./configure命令配置编译选项,例如: ``` ./configure \ --prefix=$PWD \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-openssl=../quiche/deps/boringssl \ --with-quiche=../quiche ``` 7. 编译和安装:使用make命令编译并安装nginx,例如: ``` make && make install ``` 完成以上步骤后,你就可以得到nginx-quic版本的nginx可执行文件。请注意,这些步骤可能会遇到一些问题,你可以参考\[2\]和\[3\]提供的链接获取更详细的信息和指导。 #### 引用[.reference_title] - *1* [如何在 Nginx 中启用 HTTP 3.0/QUIC 支持](https://blog.csdn.net/easylife206/article/details/112975714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Nginx支持quic协议](https://blog.csdn.net/liucy007/article/details/129383417)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Nginx官方nginx-quic搭建](https://blog.csdn.net/qq_37177958/article/details/120444034)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值