不要迷信 QUIC

很多人都在强调 QUIC 能解决 HoL blocking 问题,不好意思,我又要泼冷水了。假设大家都懂 QUIC,不再介绍 QUIC 的细节,直接说问题。

和 TCP 一样,QUIC 也是一个基于连接的,保序的可靠传输协议,TCP 的问题,QUIC 本质上都存在,只是看谁的处理方式更合理更优雅些,不存在彻底解决。QUIC 并没有解决 HoL blocking,只是缓解。里外高低都得先从多路复用开始说。

QUIC 多路复用指的是可以将多条 stream 封装在同一个 QUIC packet 中,或换句话说,多条 stream 可以通过同一条 QUIC connection 承载。

至于为什么非要多路复用,与 HTTP 相关,参考从【这里】开始往后的段落。

若只有 1 条 stream A,QUIC 与 TCP 无异,传输 A1~A100 这 100 个 packet,若 A2 丢了(or 乱序),传输会停滞,receiver 在 hole 未补充前无法交付数据,这就是 HoL blocking。

若一条 QUIC connection 承载 3 条 stream,记为 A,B,C,可有以下典型布局:
在这里插入图片描述
第一种布局,只要丢一个 packet,3 条 stream 全部 HoL blocking,第二种,第三种布局下丢一个 packet 只影响一条 stream,但它并不比多条 TCP 好多少,虽确实减少了握手开销,但也带来了问题。第二种情况属于 fair sharing,它延迟了所有 stream,将每条流的传输延时摊派到所有 3 条流的总传输延时,第三种情况属于 run-to-completion,只是简单将 3 条路串行化。

有两种典型丢包模式,随机丢和密集丢,随机丢情况下,按照中心极限定理,所有 stream 同等概率遭遇 HoL blocking,而密集丢情况下,中心极限定理依然起作用,只是影响时间跨度更大。无论如何,采用单条多路复用 QUIC connection 和采用多条 TCP 相比,在传输层面没有任何改变。

TCP 的问题在于它无法获取网络快照,在同样背景信息下,QUIC 也好不到哪里去。 无法预知网络丢包模式,千万不要猜测或假设网络丢包模式,这只会让结果偏离统计期望。采用随机布局是最好的,比如 AABBBACCCBCAABBAAAABCCBBA,这和多条 TCP 有什么不同呢?

QUIC 并没有解决 HoL blocking,只是缓解。但即便是缓解 HoL blocking,QUIC 多路复用也不如 receiver 的 Out-Of-Order Queue 作用更大,ofo Queue 提供了一个 buffer 用来松散保序约束,这才是抓住了本质,若非如此,GBN 才是真正受 HoL blocking 之大害。

此外,实际场景中,stream 数量倾向于少,而丢包乱序倾向于多,这往两边拉,QUIC 解决 HoL blocking 的解释更苍白无力。

那么 QUIC 多路复用的意义到底在哪里?

【这里】我曾说过,QUIC 是从 HTTP 协议演化而来的,当然适配它诞生的水土,HTTP 请求的一个页面上有 jpg,text,javascript 等多种元素,将这些打包在一起再合适不过。QUIC 并不适合传输单个大文件,它简直就是针对 HTTP 的。HTTP/2 提出了二进制分帧,多个资源可以整合在一起传输,但依然沿用了 TCP,整个请求被单一 TCP 连接承载,HoL blocking 问题非常明显。

解决 HTTP/2 HoL blocking 的思路是既然分帧层自己知道多路复用细节,就让分帧层自己处理单独 stream 的 HoL blocking,而不是 TCP 去处理,TCP 不识别 stream,它自身只是一条 stream。就这样,QUIC 诞生了。收到 p2,p3,p4,p5,p8,p10,丢了 p1,p6,p7,p9,对于 TCP,这些数据一个字节也没法交付,全堵在 rcvbuff,而对于 QUIC,也许可交付一部分数据,比如恰好同一个 stream 在收到的 packet 中而没包含在丢失的 packet 中,但也只是也许可以交付,不能保证。

QUIC 只是缓解了 HTTP/2 的 TCP HoL blocking。可为什么不用多条 TCP?为什么不能为每个资源创建一条 TCP 连接?

用进程/线程,协程来解释再恰当不过。指令流是一条需保序可靠执行的串行流。

TCP 和进程/线程一样,是系统感知的,创建一条 TCP 连接,需要握手时间开销,还需要生命周期内连接状态的空间开销,就好比创建一个进程需要生成 PCB 的时间开销,保存 PCB 需要空间开销,都是系统开销,它们的时空复杂度都是 O(n),无论 TCP 连接还是进程/线程,都不可扩展。

因此,为每个请求创建一个进程或线程的 MPM 方案基本都被淘汰了,工人们倾向于在固定数量的进程中处理任意数量的请求,比如 Nginx 就是这种架构。在编程 API 层面上,这就是协程。

协程是系统不感知的,因此也就没有系统开销。QUIC 中的 stream 就是传输协议中协程,QUIC 就是基于 “协-stream” 的多路复用传输协议。

在执行过程中,协程并不比多进程/多线程更快,在很矬的 CPU 上,协程的效果可能还要更差,协程的优势在于资源整合和调度,而非执行效率。与此一致,QUIC 并不比多条 TCP 更快,QUIC 可能确实修正了 TCP 的一些硬伤,比如 SACK blocking 的限制,rwnd 的限制等,但这种 patch 式修正终究改变不了太多,QUIC 的优势亦在资源整合和调度。
我来梳理一下整个故事,TCP 故事里纯背锅。

1997 年 RFC2068 定义的 HTTP/1.1 并没有强制 HTTP 一定要被 TCP 承载:

HTTP communication usually takes place over TCP/IP connections. The default port is TCP 80, but other ports can be used. This does not preclude HTTP from being implemented on top of any other protocol on the Internet, or on other networks. HTTP only presumes a reliable transport; any protocol that provides such guarantees can be used; the mapping of the HTTP/1.1 request and response structures onto the transport data units of the protocol in question is outside the scope of this specification.

注意关键句子 “HTTP only presumes a reliable transport”,彼时除了 TCP 并没有任何成熟的 “reliable transport”(当然,现在也就多了个 QUIC),只好借 TCP 承载 HTTP/1.1。

是 HTTP/1.1 先遭遇了 HoL blocking 而不是 TCP,即时不丢包场景,在 1G 的 text 后跟一个 1K 的 jpg 是一个典型的 HoL blocking case,因为 HTTP Request/Response 必须串行,而 Request 并不知道 text 和 jpg 的大小。如果 Request 知道 jpg 只有 1K,肯定会先请求 jpg,从而解除 HoL blocking。

为 HTTP/1.1 加个二进制分帧层,将文件分片混合传输,就解决了问题,由于此时依然没有除 TCP 外的 reliable transport,加上 HTTP over TCP 已默认成准则,HTTP/2 沿用了 TCP 作为承载协议。这时才遇到 TCP 的 HoL blocking 问题。

缓解(再也不要说解决) TCP HoL blocking 的直接方案就是创建多条 TCP 连接。虽然粒度较粗,但和 “多线程解决单线程 IO 等待的 HoL blocking” 的方法如出一辙。紧接着,出现新的问题,创建多条 TCP 的开销过大,这和多进程,多线程系统开销过大也是同样的嘈点。可以预料,解决问题的思路也一样。

HTTP/3 选择 QUIC 作为传输层,和多条 TCP 连接缓解 HoL blocking 效果相当,但解决了可扩展性问题,消去了 O(n) 增长的 TCP 连接管理开销。

这就是整个故事梗概,TCP 从最开始作为受命托付者,承载 HTTP 20 年,最后却被吐槽,被 QUIC “取而代之”。但实际上,这哪是 TCP 的锅,这是 HTTP 的锅啊。

保序传输本身就是顺序依赖,必须串行解除,这意味着 HoL blocking 是其内秉属性,而非问题。事实上,假如(只是假如)为 HTML 超链接资源加上 size 属性,浏览器便可在少量 TCP 连接上按某种策略 “调度” 资源的 Request,比如 SRPT(Shortest Remaining Processing Time),优先请求最小的资源,就像在 4 个 CPU 上调度 N 个进程一样,总有最优解。

超链接资源支持 size 显然很难,动态获取则需额外一个 RTT,但创建多条 TCP,并行请求多个资源,依然还是调度问题。HTTP 缺的不是一个解决 HoL blocking 问题的传输协议,因为没有这样的协议,HTTP 是个资源池,缺的是调度器。

在公网,QUIC 取代 TCP 的呼声高涨,而老教授 John Ousterhout 也在喷 TCP 不适合 DC。但 TCP 大概率不会消失,无论是 HTTP-Oriented QUIC,or RPC-Oriented Homa,都无法取代 Everything-Oriented TCP,TCP 不假设任何先验,它的意义不是在资源充盈的时候表现得多好,而是最坏的情况下它不至于太糟糕。

当然,QUIC 有很多相对 TCP 的优势,不然它就没有存在的必要了,本文的主旨是,看到不足,才知进步。

HoL blocking 是串行流的内在属性,无论对指令流的执行还是 byte stream 的传输,本质都一样,都是保序流,保序流意味着顺序依赖,且这种顺序只允许唯一一种可能性,降低了容错空间,HoL blocking 对效率的影响显而易见。但经常听到 “QUIC 解决了 HoL blocking” 的说法,需要澄清一下了。最近在读 《布匿战争》,执政官 A 从墨西拿海峡率领 2 个军团纵贯狭长的意大利半岛赶去阿尔卑斯山南麓驰援执政官 B,如何行军最快?列队行军吗?执政官 A 对军团下令,就地解散,个人或结伴自行北上,到达执政官 B 附近后重新列队。这就是乱序传输了,解除了顺序依赖,效率自然高。

浙江温州皮鞋湿,下雨进水不会胖。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【测试开发篇4】测试模型

目录 一、软件测试V模型 编码前 概要设计: 详细设计: 编码后: 单元测试&集成测试 系统测试 验收测试 V模型的特点 优点: 缺点: 二、软件测试W模型 编码之前: 编码的时候: 编…

全网最详细,Jmeter性能测试数据写入文件(总结)看这篇就够了......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 jmeter 性能测试数据…

RK3568平台开发系列讲解(Linux系统篇)消息队列

🚀返回专栏总目录 文章目录 一、创建消息队列二、发送和接收消息三、内核结构沉淀、分享、成长,让自己和他人都能有所收获!😄 📢消息队列在如下两个方面上比管道有所增强: 消息队列中的数据是有边界的,发送端和接收端能以消息为单位进行交流,而不再是无分隔的字节流…

Android---动态权限申请

目录 权限分类 动态权限核心函数 简易实现案例 完整代码 Google 在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。App 每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。 权限分类 系统权限分为两类:正常…

队列实现及leetcode相关OJ题

上一篇写的是栈这一篇分享队列实现及其与队列相关OJ题 文章目录一、队列概念及实现二、队列源码三、leetcode相关OJ一、队列概念及实现 1、队列概念 队列同栈一样也是一种特殊的数据结构,遵循先进先出的原则,例如:想象在独木桥上走着的人&am…

计算机网络管理 TCP三次握手的建立过程,Wireshark抓包分析并验证TCP三次握手建立连接的报文

⬜⬜⬜ ---🟧🟨🟩🟦🟪 (*^▽^*)欢迎光临 🟧🟨🟩🟦🟪---⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu 🎁欢迎各位→…

【Linux入门篇】操作系统安装、网络配置

目录 🍁Linux详解 🍂1.操作系统 🍂2.操作系统组成 🍂3.操作系统历史 🍂4.常见的Linux系统 🍂5.centos7下载 🍂6.安装centos7 🍁linux初始化配置 🍃1.虚拟机系统安装后操作…

从零实现深度学习框架——学习率调整策略介绍

引言 本着“凡我不能创造的,我就不能理解”的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导。 要深入理解深度学习,从零开始创建的经验非常重要,从自己可以理解的角度出发,尽量不使用外部完备的框架前提下,实现我…

【微信小程序】-- 案例 - 自定义 tabBar(四十六)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…

kali内置超好用的代理工具proxychains

作者:Eason_LYC 悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。 一个人的价值,在于他所拥有的。所以可以不学无术,但不能一无所有! 技术领域:WEB安全、网络攻防 关注WEB安全、网络攻防。…

31. 下一个排列

题目链接:https://leetcode.cn/problems/next-permutation/解题思路:整数数组的 下一个排列 是指其整数的下一个字典序更大的排列,其实也就是把整数所有数字从左往右组合成一个数,则下一个排列就是将数组中的所有元素重新组合成一…

【跟着chatgpt学go】Gooutine和Channel

Goroutine Goroutine 是 Go 语言中的一种并发机制,它是一种轻量级线程,可以通过关键字 go 启动一个新的 Goroutine。相比传统的线程,Goroutine 拥有更小的栈空间,因此可以创建更多的 Goroutine。 下面是一个简单的 Goroutine 的…

数据结构初阶(顺序表)

文章目录1、时间复杂度1.2、大O渐进表示法1.3、递归算法时间复杂度计算2、空间复杂度3、顺序表1、概念2、静态顺序表3、动态顺序表1、创建结构体(头文件中创建)2、销毁链表3、初始化结构体4、打印函数5、内存扩容6、顺序表任意位置插入数据7、顺序表任意…

从 hybrid开发----》微前端

为什么开始写关于微前端的一系列博客? 1. 学生时代讨论关于hybrid APP的应用开发,历史的选择总是变化的,需要更进一步深入。 2. 之前工作项目中见到过沙箱隔离之后CSS冲突,需要学一下如何解决 ----------------------------- …

QT CTK插件框架 (一 下载编译)

CTK 为支持生物医学图像计算的公共开发包,其全称为 Common Toolkit。为医学成像提供一组统一的基本功能;促进代码和数据的交互及结合;避免重复开发;在工具包(医学成像)范围内不断扩展到新任务,而…

ChatGPT助力校招----面试问题分享(四)

1 ChatGPT每日一题:电阻如何选型 问题:电阻如何选型 ChatGPT:电阻的选型通常需要考虑以下几个方面: 额定功率:电阻的额定功率是指电阻能够承受的最大功率。在选型时,需要根据电路中所需要的功率确定所选…

【JavaEE】Thread 类及常用方法

一、Thread 类Thread 类我们可以理解为是 java 用于管理线程的一个类,里面封装了操作系统提供的线程管理这一方面的 API (Thread 是优化后的结果), Java 代码创建的每一个线程,可以理解为为 Thread 实例化的对象,Threa…

JUC是什么?

JUC 简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的。JUC 就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包,JDK 1.5 开始出现的。 进程与线程 进程(Process) 是计算机中…

Java基础:笔试题

文章目录Java 基础题目1. 如下代码输出什么?2. 当输入为2的时候返回值是多少?3. 如下代码输出值为多少?4. 给出一个排序好的数组:{1,2,2,3,4,5,6,7,8,9} 和一个数,求数组中连续元素的和等于所给数的子数组解析第一题第二题第三题第四题方案…

[ 云计算 | Azure ] Chapter 05 | 核心体系结构之管理组、订阅、资源和资源组以及层次关系

本文主要对如下内容进行讲解:Azure云计算的核心体系结构组件中的:资源、订阅和资源组,以及了解 Azure 资源管理器 (ARM) 如何部署资源。 本系列已经更新文章列表: [ 云计算 | Azure ] Chapter 03 | 描述云计算运营中的 CapEx 与…