谷歌出品!读懂 QUIC 协议:更快、更高效的通信协议

news2024/11/17 7:22:19
QUIC结构

QUIC协议模型如下图所示,其放弃了TCP∕IP网络中使用五元组(源IP,源端口,目的IP,目的端口,协议标识符)来唯一标识一条连接的方式,而使用一个全局唯一的随机生成的ID(即Connection ID) 来标识一条连接。

由低向上分层讨论QUIC协议:

•UDP层:在UDP层传输的是UDP报文,此处关注的是UDP报文荷载内容是什么,以及如何高效发送UDP报文;

•Connection层:Connection通过Connection ID来确认唯一连接,connection对packet进行可靠传输和安全传输;

•Stream层:在相应的Connection中,Stream通过Stream ID进行唯一流确认,并对stream frame进行传输管理。

Quic协议相关术语
  • 数据包(Packet):QUIC 协议中一个完整可处理的单元,可以封装在UDP 数据报(datagram)中。多个QUIC 数据包(packets)可以封装在一个UDP 数据报(datagram)中。
  • 帧(Frame):QUIC 数据包(packet)的有效载荷(payload)。
  • 端点(Endpoint):在QUIC 连接中生成、接收和处理 QUIC 数据包(packets)的终端。QUIC中只有两端点(endpoints):客户端(client)和服务端(server)。
  • 客户端(Client): 创建QUIC 连接的端点。
  • 服务端(Server): 接收QUIC 连接的端点。
  • 地址(Address):未经限定使用时,表示网络路径一端的IP 版本、IP地址和 UDP 端口号的元组。
  • 连接ID(Connection ID): 用于标识端点 QUIC 连接的一种标识符。每个端点(endpoint)为其对端(peer)选择一个或多个连接 ID,将其包含在发送到该端点的数据包(packets)中。这个值对peer 不透明。
  • 流(Stream):QUIC 连接中有序字节的单向(unidirectional)或双向(bidirectional)通道。一个QUIC 连接可以同时携带多个流。
  • 应用程序(Application):使用QUIC 发送或者接收数据的实体。
UDP层
UDP荷载大小

•荷载大小受限于3个对象:QUIC协议规定;路径MTU;终端接受能力

1、QUIC不能运行在不支持1200字节的单个UDP传输网络路径上 QUIC规定initial包大小不得小于1200,如果数据本身不足1200(比如initial ack),那么需要用padding方式至少填充到1200字节

2、QUIC不希望出现IP层分片现象本要求意味着udp交给IP层的数据不会大于1个MTU,假设mtu为1500,ipv4场景下,udp的荷载上限为1472字节(1500-20-8),ipv6下,udp荷载上限为1452(1500-40-8)。QUIC建议使用PMTUD以及DPLPMTUD进行mtu探测。在实战中,我们建议设置IPv6的MTU为1280,大于这个值,某些网络会存在丢包现象。

3、终端能接受 transport paraments的max_udp_payload_size(0x03)的是终端接受单个udp包大小的能力,发送端应当遵从这一约定。

UDP荷载内容

UDP荷载内容即为QUIC协议中的packet。协议规定,如果不超过荷载大小的限制,那么多个packet可以组成一个UDP报文发出去。在QUIC实现中,如果每个UDP报文只包含一个QUIC packet,会更容易出现乱序问题。

高效发UDP包

和tcp不同,QUIC需要在应用层就完成UDP数据组装,且每个udp报文不大于1个mtu,如果不加以优化,比如每个包直接用sendto/sendmsg发送,势必会造成大量的系统调用,影响吞吐

1、通过sendmmsg接口进行优化,sendmmsg可以将用户态的多个UDP QUIC包通过一次系统调用发到内核态。内核态对于每个UDP QUIC包独立作为UDP包发出去

2、在1.)解决了系统调用次数问题,开启GSO可以进步一分包延迟到发给网卡驱动前一刻,可以进一步提高吞吐,降低CPU消耗。

Connection层

上节说到,1个udp报文里传输的其实是一个或多个QIUC协议打包的packet。所以在Connection这一层面,其实是以packet为单位进行管理的。一个packet到来,终端需要解析出目标Connection ID(DCID)字段,并将该packet交给找到对应的QIUC connection。一个packet是由header加payload两部分组成。

Connection ID

相较于TCP/IP使用五元组标识一条连接,QIUC在Connection层采用客户端随机产生的64位随机数作为Connection ID标识连接,这样IP或者端口发生变化时,只要ID 不变,这条连接依然维持,可以做到连接平滑迁移。

连接建立时使用UDP端口号来识别指定机器上的特定server,而一旦建立,连接通过其connection ID关联。

上图左边是HTTPS的一次完全握手的建连过程,需要3 个 RTT。就算是Session Resumption,也需要至少 2个 RTT。而 QUIC 由于建立在UDP 的基础上,同时又实现了 0RTT的安全握手,所以在大部分情况下,只需要0 个 RTT就能实现数据发送,在实现前向加密的基础上,并且 0RTT 的成功率相比TLS 的 Sesison Ticket要高很多。QUIC握手(handshake)合并了加密和传输参数的协商,只需要1-RTT 即可完成握手,提升了建立连接到交换应用程序数据的速度。第二次连接时,可以通过第一次连接时获取到的预共享密钥(pre-shared secret)立即发送数据(0-RTT)。

安全传输

QUIC的安全传输依赖TLS1.3,而boring ssl是众多quic实现的依赖库。协议对Packet的头部以及荷载均进行了保护(包括packet number)。TLS1.3提供了0-RTT的能力,在提供数据保护的同时,能在第一时间(服务端收到第一个请求报文时)就将Response Header发给客户端。大大降低了HTTP业务中的首包时间。为了支持0-RTT,客户端需要保存PSK信息,以及部分transport parament信息。

安全传输也经常会涉及到性能问题,在目前主流的服务端,AESG由于cpu提供了硬件加速,所以性能表现最好。CHACHA20则需要更多的CPU资源。在短视频业务上,出于对首帧的要求,通常直接使用明文传输。

Transport Paramenter(TP)协商是在安全传输的握手阶段完成,除了协议规定的TP外,用户也可以扩展私有TP内容,这一特性带来了很大的便利,比如:客户端可以利用tp告知服务端进行明文传输。

可靠传输

QUIC协议是需要像TCP能够进行可靠传输,所以QUIC单独有一个rfc描述了丢包检测和拥塞控制的话题,

  • 丢包检测:

TCP 为了保证可靠性,使用了基于字节序号的 Sequence Number 及 Ack 来确认消息的有序到达。

QUIC 同样是一个可靠的协议,它使用 Packet Number 代替了 TCP 的 sequence number,并且每个 Packet Number 都严格递增。而 TCP ,重传 segment 的 sequence number 和原始的 segment 的 Sequence Number 保持不变,也正是由于这个特性,引入了 TCP 重传的歧义问题。

在普通的TCP里面,如果发送方收到三个重复的ACK就会触发快速重传,如果太久没收到ACK就会触发超时重传,而QUIC使用NACK (Negative Acknowledgement) 可以直接告知发送方哪些包丢了,不用等到超时重传。TCP有一个SACK的选项,也具备NACK的功能,QUIC的NACK有一个区别它每次重传的报文序号都是新的。

但是单纯依靠严格递增的 Packet Number 肯定是无法保证数据的顺序性和可靠性。QUIC 又引入了一个 Stream Offset 的概念,即一个 Stream 可以经过多个 Packet 传输,Packet Number 严格递增,没有依赖。但是 Packet 里的 Payload 如果是 Stream 的话,就需要依靠 Stream 的 Offset 来保证应用数据的顺序。

  • 拥塞控制:QUIC针对TCP协议中的一些缺陷,专门做了优化。QUIC 重新实现了TCP 协议的Cubic算法进行拥塞控制,并在此基础上做了不少改进。
  • 热插拔:tcp的拥塞控制需要内核态实现,而QUIC在用户态实现,因此QUIC 修改拥塞控制策略只需要在应用层操作,并且QUIC 会根据不同的网络环境、用户来动态选择拥塞控制算法。
  • 前向纠错 FEC:QUIC 使用前向纠错(FEC,Forward Error Correction)技术增加协议的容错性。一段数据被切分为10 个包后,依次对每个包进行异或运算,运算结果会作为 FEC 包与数据包一起被传输,当出现丢包时可根据剩余的包和FEC包推算出丢的包。
单调递增的Packet Number

TCP 为了保证可靠性,使用Sequence Number 和 ACK确认消息是否有序到达,但这样的设计存在缺陷。超时发生后客户端发起重传,随后接收到了ACK确认,但因为原始请求和重传请求所返回的ACK 消息一样,所以客户端无法分辨此 ACK 对应的是原始请求还是重传请求。如果客户端认为是原始请求的ACK,但实际上是左图的情形,则计算的采样 RTT 偏大;如果客户端认为是重传请求的ACK,但实际上是右图的情形,又会导致采样 RTT 偏小。采样 RTT 会影响超时重传时间(Retransmission TimeOut)的 计算。

QUIC解决了上面的歧义问题。与采用Sequence Number 标记不同的是,其使用的Packet Number标记严格单调递增,如果 Packet N 丢失了,那么重传时 Packet 的标识不会是 N,而是比 N 大的数字,比如N+M,这样发送方接收到确认消息时就能方便地知道 ACK 对应的是原始请求还是重传请求。

Connection层
更大的ACK block

一般来说,接收方收到发送方的消息后都应该发送一个 ACK回复,表示收到了数据。但每收到一个数据就返回一个ACK 回复太麻烦,所以一般不会立即回复,而是接收到多个数据后再回复,TCP SACK 最多提供 3个 ACK block。但有些场景下,比如下载,只需要服务器返回数据就好,但按照 TCP 的设计,每收到 3 个数据包就要返回一个ACK。而QUIC 最多可以捎带 256 个ACK block。在丢包率比较严重的网络下,更多的 ACK block 可以减少返回包的量,提升网络效率。

流量控制

TCP 会对每个 TCP 连接进行流量控制,通过滑动窗口进行实现。

QUIC 的流量控制有两个级别:连接级别和Stream级别,用于表达接收端的接受能力。

单条 Stream的流量控制如上图所示。Stream 还没传输数据时,接收窗口(flow control receive window)就是最大接收窗口(flow control receive window),随着接收方接收到数据后,接收窗口不断缩小。在接收到的数据中,有的数据已被处理,而有的数据还没来得及被处理。蓝色块表示已处理数据,黄色块表示未处理数据,这部分数据的到来,使得Stream的接收窗口缩小。

随着数据不断被处理,接收方就有能力处理更多数据。当满足(flow control receive offset - consumed bytes) < (max receive window / 2) 时,接收方会发送WINDOW_UPDATE frame 告诉发送方你可以再多发送些数据过来。这时flow control receive offset就会偏移,接收窗口增大,发送方可以发送更多数据到接收方。

由于QUIC协议允许多路复用,因此Stream 级别的控制对防止接收端接收过多数据作用有限,更需要借助 Connection 级别的流量控制。

针对stream:

可用窗口数 = 最大窗口数 – 接收到的最大偏移数

针对connection:

可用窗口数 = stream1可用窗口数+ … + streamN可用窗口数

QUIC 的流量控制和TCP 有点区别,TCP为了保证可靠性,窗口左边沿向右滑动时的长度取决于已经确认的字节数。如果中间出现丢包,就算接收到了更大序号的Segment,窗口起始changdu也无法超过这个序列号。 QUIC 不同,就算此前有些 packet 没有接收到,它的滑动窗口也只取决于接收到的最大偏移字节数。

Stream层

Stream是一个抽象的概念,用以表示一个有序传输的数据流,而这些数据其实就是由Stream Frame排列构成。QUIC 使用帧(frames)进行端到端的通信。一个或多个帧(frame)被组装成一个 QUIC 包(packet)。在一个quic connection上,可以同时传输多条流,QUIC通过对多路传输的支持,解决了TCP中的队头阻塞问题。

在QUIC协议中,有序的概念仅维护在单个stream中,stream之间和packet都不要求有序,假设某个packet丢失,只会影响包含在这个包里的stream,其他stream仍然可以从后续乱序到达的packet中提取到自己所需帧交给应用层。

Stream头部

可以创建两种类型的流:双向流(bidirectional streams),允许客户端和服务端互相发送数据。单向流(unidirectional streams),允许单个端点(endpoint)发送数据。一个基于信用的方案(credit-based scheme)用于限制流的创建并限制可发送的数据量。stream的不同类型定义在HTTP3中得到了充分的利用。

Stream荷载

Stream的荷载即为一系列Stream Frame,通过Stream Frame头部的Stream ID来确认单个流。在TCP里,如果一个segment传递丢失,那么后续segment乱序到达,也不会被应用层使用,只到丢失的segment重传成功为止,因此TCP实现的HTTP2的多路复用能力受到制约。在QUIC协议中,有序的概念仅维护在单个stream中,stream之间和packet都不要求有序,假设某个packet丢失,只会影响包含在这个包里的stream,其他stream仍然可以从后续乱序到达的packet中提取到自己所需要的数据交给应用层。

Quic相关开源库
gQUICiQUIC
chromium:quic-client/server-demo模块封装了支持HTTPS的QUIC实现MsQuicMsQuic是IETF quic协议的Microsoft实现。它是跨平台的,用C语言编写,设计成一个通用的QUIC库。
chromium:net/quic模块封装QUIC在更底层模仿TCP Socket操作,在chrome75版本后被弃用,本次quic模块基于74-75版本的模块实现。quic-go使用Go语言来重写的QUIC协议实现库,从github上面看其对于iQUIC和gQUIC这两个分支流派都提供了支持。
quiche目前谷歌使用的QUIC开源代码库,将QUIC从chromium独立出来提供QUIC协议的支持,与iQUIC兼容。QuicwgIETF quic实现工作小组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1411053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

心理学大纲

简介 psychology&#xff0c;“psyche”(ψυχή):意为"soul"(灵魂)&#xff0c;即对我们灵魂的研究 我的学习的目的 了解人精神世界的模型&#xff0c;人格的形成]&#xff0c;作为观察分析他人内心的理论指导&#xff0c;便于我实践了解情绪的机理&#xff0c;…

vue---打印本地当前时间Demo

<template><view class"content" tap"getCurrentTime()">打印时间</view> </template><script>export default {data() {return {title: Hello}},onLoad() {},methods: {getCurrentTime() {//获取当前时间并打印var _this …

【驱动】TI AM437x(内核调试-07):devmem2直接读写内存、寄存器,devkmem读取内核变量

1、/dev/mem 和 /dev/kmem 1)/dev/mem: 物理内存的全镜像。可以用来访问物理内存 2)/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。kernel部分内存用户空间本不可访问。但是因为所有进程共享内核空间的页表。所以内核虚拟地址对应物理地址是确定的…

紫光展锐T760_芯片性能介绍_展锐T760安卓核心板定制

展锐T760核心板是一款基于国产5G芯片的智能模块&#xff0c;采用紫光展锐T760制程工艺为台积电6nm工艺&#xff0c;支持工艺具有出色的能效表现。其采用主流的44架构的八核设计&#xff0c;包括4颗2.2GHz A76核心和4颗A55核心设计&#xff0c;内存单元板载可达8GB Ram256GB ROM…

【Java基础】JVM关闭回调函数(ShutdownHook)的应用场景

文章目录 一.ShutdownHook介绍二.ShutdownHook被调用场景三.ShutdownHook如何使用四.ShutdownHook实践 一.ShutdownHook介绍 ShutdownHook就是一个简单的 已初始化 但是 未启动 的 线程 。当虚拟机开始关闭时&#xff0c;它将会调用所有已注册ShutdownHook的回调函数&#xff0…

x-cmd pkg | sqlite3 - 轻量级的嵌入式关系型数据库

目录 简介首次用户 技术特点竞品和相关产品sqlite 与 x-cmd进一步阅读 简介 sqlite3 是一个轻量级的文件数据库&#xff0c;体积非常小&#xff0c;提供简单优雅而功能强大的 sql 化的数据查询。 通常情况下&#xff0c;sqlite 指的是 SQLite 2.x 版本&#xff0c;而 sqlite3 …

【WPF.NET开发】WPF 中的 Layout

本文内容 元素边界框布局系统测量和排列子元素面板元素和自定义布局行为布局性能注意事项子像素渲染和布局舍入 本主题介绍 Windows Presentation Foundation (WPF) 布局系统。 了解布局计算发生的方式和时间对于在 WPF 中创建用户界面非常重要。 1、元素边界框 在 WPF 中构…

unity学习笔记----游戏练习07

一、僵尸攻击和植物的掉血和销毁 当僵尸接触到植物开始攻击时会持续削减植物的血量&#xff0c;当植物血量为零时就销毁当前植物。 在plantManager中&#xff0c; 为植物添加一个血量HP 100&#xff0c; public int HP 100; 在写一个减少血量的方法&#xff0c;来减少血…

安全防御第三次作业

作业&#xff1a;拓扑图及要求如下图 注&#xff1a;server1是ftp服务器&#xff0c;server2是http服务器 lsw1&#xff1a; 其中g0/0/0口为trunk 实现 1&#xff0c;生产区在工作时间内可以访问服务器区&#xff0c;仅可以访问http服务器 验证&#xff1a; 2&#xff0c;办公…

代码随想录算法训练营第二十七天|455.分发饼干 , 376. 摆动序列 , 53. 最大子序和

455.分发饼干 代码随想录 class Solution {public int findContentChildren(int[] g, int[] s) {int ans 0;Arrays.sort(g);Arrays.sort(s);int start s.length - 1;for (int i g.length - 1; i >0; i--) {if (start > 0 && s[start] > g[i]) {ans;start…

精要图示:园区金融数字化服务蓝图,以园区为支点推动信贷业务增长

作为企业集聚地&#xff0c;园区已然成为银行业夯实客群基础的重要切口&#xff0c;各大行陆续围绕园区场景创新金融产品&#xff0c;以期抢跑园区金融新赛道、把握新增量。 启信慧眼首推一站式【园区金融】数字化服务方案&#xff0c;该方案同时支持启信天元私有化部署&#x…

idea 打包跳过测试

IDEA操作 点击蓝色的小球 手动命令 mvn clean package -Dmaven.test.skiptrue

水波浪标题

上图效果要先复制第13次修改的备忘录&#xff0c;再另外保存下面的代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <a class"a-href a-h">水波浪标题</a> <style>.h1-div {/* 隐藏 */display: none;}h1 {display: inli…

【干货】【常用电子元器件介绍】【电阻】(二)--敏感电阻器

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。   电子电路中除了采用普通电阻器外&#xff0c;还有一些敏感电阻器&#xff08;如热敏电阻器、压敏电阻器、光敏电阻器等&#xff09;也被广泛地应用。然而…

直播核心岗位基础内容

一.直播间核心岗位 1.直播间前端岗位 前端岗位分工 &#xff08;1&#xff09;主播岗位职责 &#xff08;2&#xff09;场控岗位职责 &#xff08;3&#xff09;助理岗位职责 中端岗位分工 &#xff08;1&#xff09;运营岗位职责 &#xff08;2&#xff09;中控岗位职责 …

C# 使用AutoMapper实现类映射

写在前面 AutoMapper是一个用于.NET中简化类之间的映射的扩展库&#xff1b;可以在执行对象映射的过程&#xff0c;省去的繁琐转换代码&#xff0c;实现了对DTO的快速装配&#xff0c;有效的减少了代码量。 通过NuGet安装&#xff0c;AutoMapper&#xff0c; 由于本例用到了D…

【Unity】粒子贴图异常白边问题

从PS制作的黑底&#xff0c;白光的贴图。放入Unity粒子中&#xff0c;拉远看会有很严重的白边&#xff0c;像马赛克一样。 材质使用&#xff1a;Mobile/Particles/Additive 经测试只使用一张黑色的图片&#xff0c;也会有白边。 解决方案&#xff1a; 关闭黑色底&#xf…

RX4901CE (RTC模块)

RX4901CE是一个集成了32.768 kHz数字温度补偿晶体振荡器(DTCXO)的RTC模块。高稳定性&#xff0c;低电流消耗&#xff0c;时间戳功能&#xff0c;当外部或内部事件发生时&#xff0c;可以记录多达32个日期和时间&#xff0c;以及基本的RTC功能&#xff0c;如时间和日历&#xff…

什么是servlet

什么是servlet 什么是servlet Servlet&#xff08;Server Applet&#xff09;是 Java Servlet 的简称&#xff0c;称为小服务程序或服务连接器&#xff0c;用 Java 编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c;主要功能在于交互式地浏览和生成数据…

对话泛能网程路:能源产业互联网,行至中程

泛能网的能源产业互联网的标杆价值还不仅于此。其在产业互联之外&#xff0c;也更大的特殊性在于其也更在成为整个碳市场的“辅助运营商”&#xff0c;包括电力、碳等一系列被泛能网帮助企业改造和沉淀的要素资产&#xff0c;都在构成着碳交易市场的未来底层。 这恰是产业互联…