异步为什么会造成 HTTP 队首阻塞?
一、http 协议的队首阻塞
队首阻塞,队首的事情没有处理完的时候,后面的都要等着。
1.1 HTTP1.0 的队首阻塞
对于同一个 tcp 连接,所有的 http1.0 请求放入队列中,只有前一个请求的响应收到了,然后才能发送下一个请求。http1.0 的队首组塞发生在客户端。
1.2 HTTP1.1 的队首阻塞
HTTP1.1 版本上使用了一种 Pipelining 管道技术来并行发送和处理多个请求。让客户端能够并行发送多个请求,服务器端也可以并行处理多个来自客户端的请求。在一个 TCP 连接中,发送多个 HTTP 请求,不需要等待服务器端对前一个请求的响应之后,再发送下一个请求。但是使用了管道技术的 HTTP/1.1,根据 HTTP/1.1 的规则,服务器端在响应时,要严格按照接收请求的顺序发送,即先接收到的请求,需要先发送其响应,客户端浏览器也是如此,接收响应的顺序要按照自己发送请求的顺序来。这样造成的问题是,如果 最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队首阻塞。
总的来说,管道技术允许客户端和服务器端并行发送多个请求和响应,但是客户端接收响应的顺序要和自己发送请求的顺序对应,服务器端发送响应的顺序要和自己接收到的请求的顺序对应,这样做似乎没什么问题,看起来是不是“FIFO”先来先服务的方式,如果前面收到的一个请求,在服务器端处理的时间很长,生成响应需要很多时间,那么对于后面的已经处理完生成响应的请求来说,它们只能阻塞等待,等待前面的响应发送完后,自己才能被发送出去(即使该请求的响应已经生成),造成了“队首阻塞”问题。可见队首阻塞发生在服务器端,虽然服务器端并行接收了多个请求,也并行处理生成多个响应,但由于要遵守 HTTP/1.1 的规则,先接收到的请求需要先发送响应,造成了阻塞问题。
另外需要注意的是,虽然 HTTP/1.1 规范中规定了 Pipelining 管道技术来并行发送和处理多个请求,但是这个功能在浏览器中默认是关闭的。
看一下 Pipelining 是什么,RFC 2616 中的规定 A client that supports persistent connections MAY “pipeline” its requests (i.e., send multiple requests without waiting for each response). A server MUST send its responses to those requests in the same order that the requests were received. 一个支持持久连接的客户端可以在一个连接中发送多个请求(不需要等待任意请求的响应)。收到请求的服务器必须按照请求收到的顺序发送响应。 至于标准为什么这么设定,我们可以大概推测一个原因:由于 HTTP/1.1 是个文本协议,同时返回的内容也并不能区分对应于哪个发送的请求,所以顺序必须维持一致。比如你向服务器发送了两个请求 GET /query?q=A 和 GET /query?q=B,服务器返回了两个结果,浏览器是没有办法根据响应结果来判断响应对应于哪一个请求的。
Pipelining 这种设想看起来比较美好,但是在实践中会出现许多问题:
- 一些代理服务器不能正确的处理 HTTP Pipelining。
- 正确的流水线实现是复杂的
- Head-of-line Blocking 连接头阻塞:在建立起一个 TCP 连接之后,假设客户端在这个连接连续向服务器发送了几个请求。按照标准,服务器应该按照收到请求的顺序返回结果,假设服务器在处理首个请求时花费了大量时间,那么后面所有的请求都需要等着首个请求结束才能响应。
所以现代浏览器默认是不开启 HTTP Pipelining 的。
1.3 HTTP2 队首阻塞
对于 HTTP1.1 中管道化导致的请求/响应级别的队头阻塞,可以使用 HTTP2 解决。HTTP2 不使用管道化的方式,而是引入了帧、消息和数据流等概念,每个请求/响应被称为消息,每个消息都被拆分成若干个帧进行传输,每个帧都分配一个序号。每个帧在传输是属于一个数据流,而一个连接上可以存在多个流,各个帧在流和连接上独立传输,到达之后在组装成消息,这样就避免了请求/响应阻塞。
当然,即使使用 HTTP2,如果 HTTP2 底层使用的是 TCP 协议,仍可能出现 TCP 队头阻塞。因为 HTTP/2 并没有解决 TCP 的队首阻塞问题,它仅仅是通过多路复用解决了以前 HTTP1.1 管线化请求时的队首阻塞。比如 HTTP/1.1 时代建立一个 TCP 连接,三个请求组成一个队列发出去,服务器接收到这个队列之后会依次响应,一旦前面的请求阻塞,后面的请求就会无法响应。HTTP/2 是通过分帧并且给每个帧打上流的 ID 去避免依次响应的问题,对方接收到帧之后根据 ID 拼接出流,这样就可以做到乱序响应从而避免请求时的队首阻塞问题。但是 TCP 层面的队首阻塞是 HTTP/2 无法解决的(HTTP 只是应用层协议,TCP 是传输层协议),TCP 的阻塞问题是因为传输阶段可能会丢包,一旦丢包就会等待重新发包,阻塞后续传输,这个问题虽然有滑动窗口(Sliding Window)这个方案,但是只能增强抗干扰,并没有彻底解决。
二、TCP 队首阻塞
队首阻塞(head-of-line blocking)发生在一个 TCP 分节丢失,导致其后续分节不按序到达接收端的时候。该后续分节将被接收端一直保持直到丢失的第一个分节被发送端重传并到达接收端为止。该后续分节的延迟递送确保接收应用进程能够按照发送端的发送顺序接收数据。这种为了达到完全有序而引入的延迟机制非常有用,但也有不利之处。
假设在单个 TCP 连接上发送语义独立的消息,比如说服务器可能发送 3 幅不同的图像供 Web 浏览器显示。为了营造这几幅图像在用户屏幕上并行显示的效果,服务器先发送第一幅图像的一个断片,再发送第二幅图像的一个断片,然后再发送第三幅图像的一个断片;服务器重复这个过程,直到这 3 幅图像全部成功地发送到浏览器为止。
要是第一幅图像的某个断片内容的 TCP 分节丢失了,客户端将保持已到达的不按序的所有数据,直到丢失的分节重传成功。这样不仅延缓了第一幅图像数据的递送,也延缓了第二幅和第三幅图像数据的递送。
2.1 如何解决 TCP 队头阻塞
TCP 中的队头阻塞的产生是由 TCP 自身的实现机制决定的,无法避免。想要在应用程序当中避免 TCP 队头阻塞带来的影响,只有舍弃 TCP 协议。
比如 google 推出的 quic 协议,在某种程度上可以说避免了 TCP 中的队头阻塞,因为它根本不使用 TCP 协议,而是在 UDP 协议的基础上实现了可靠传输。而 UDP 是面向数据报的协议,数据报之间不会有阻塞约束。
此外还有一个 SCTP(流控制传输协议),它是和 TCP、UDP 在同一层次的传输协议。SCTP 的多流特性也可以尽可能的避免队头阻塞的情况。
三、总结
从 TCP 队头阻塞和 HTTP 队头阻塞的原因我们可以看到,出现队头阻塞的原因有两个:
- 独立的消息数据都在一个链路上传输,也就是有一个“队列”。比如 TCP 只有一个流,多个 HTTP 请求共用一个 TCP 连接
- 队列上传输的数据有严格的顺序约束。比如 TCP 要求数据严格按照序号顺序,HTTP 管道化要求响应严格按照请求顺序返回
所以要避免队头阻塞,就需要从以上两个方面出发,比如 quic 协议不使用 TCP 协议而是使用 UDP 协议,SCTP 协议支持一个连接上存在多个数据流等等。
相关文章:
异步为什么会造成 HTTP 队首阻塞?
一、http 协议的队首阻塞 队首阻塞,队首的事情没有处理完的时候,后面的都要等着。 1.1 HTTP1.0 的队首阻塞 对于同一个 tcp 连接,所有的 http1.0 请求放入队列中,只有前一个请求的响应收到了,然后才能发送下一个请求。http1.0 的…...
使用hibernate,报出ORA-00933_ SQL 命令未正确结束
这里分享一个很容易出错的原因,一旦涉及到切换不同的数据源,就需要修改配置文件,有时候就会忘记了修改方言,而jpa是需要设置方言的。 比如我这里就是因为从mysql切换为了使用oracle,忘记了设置对应的方言,才…...

易点易动设备管理系统:提升企业备件管理和维修效率的智能解决方案
在当今竞争激烈的商业环境中,大型生产制造企业面临着日益复杂的设备管理挑战。为了提高生产效率和降低成本,企业需要一种高效的设备管理系统。易点易动设备管理系统是一款智能化的解决方案,旨在帮助企业提升备件管理和维修效率。本文将详细介…...

新上线游戏产品需不需要防御?
游戏运营免不了遭受恶意DDoS和CC攻击,且攻击常达百G以上,攻击流量过大,超过一般服务器的基础防护能力,不少企业面对大流量攻击显得束手无策,只能选择被迫停机,其次游戏行业利润高,很容易被黑客盯…...

Linux中的开发工具(yum,vim,gcc/g++,gdb,Makefile,git)
文章目录 1. Linux软件包管理器——yumyum 语法yum 常用命令安装 yum 仓库源 2. Linux编辑器——vimvim 的五种常用模式模式切换vim 基本操作命令模式命令集(1)光标命令(2)复制粘贴命令(3)撤销与重做&#…...

什么是自动证书管理环境(ACME)
组织的网站需要 24x7 全天候可用,以建立信任并提供信息,如果网站因证书过期而停机,那么很难恢复失去的客户信任、收入和品牌声誉,手动管理证书基础结构会使组织面临中断、中间人 (MITM) 攻击等的严重风险。…...

探索光模块的MSA多源协议
在当今高度互联的世界中,光模块作为网络设备的重要部分,其性能和质量直接影响到整个网络系统的运行。其中光模块由于其灵活性和高效性,已经成为数据中心和云计算领域的主要选择。本文易天光通信将深入探讨光模块的MSA协议,揭示其重…...

《算法通关村——双指针妙用》
《算法通关村——双指针妙用》 删除元素 描述 给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。要求:不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组…...

postgresql|数据库迁移|ora2pg工具的web界面介绍
前言: ora2pg是一个比较强大的数据库迁移工具,那根据名字来说,也可以看出来,这个工具主要是用来配置去O化,将在运行的oracle数据库迁移到postgresql数据库内的 当然了,我们使用此工具主要还是用命令行&am…...
【zookeeper】zk的ZAB原子广播协议
zk的ZAB原子广播协议来源于paxos算法[1]。paxos算法是一种基于消息传递的消息一致性算法,其特点是在可靠的通信环境下,可以保证消息的最终一致性。paxos要求每台server都持有自己的一个事务id的记录,这个事务id会每通过一个提议就自增加一&am…...

【问题思考总结】为什么分布函数右连续要左闭右开
问题 这个问题困扰我很久了,虽然感觉没什么用,但是还是想着搞清楚一点。 思考 Q1:什么是右连续? A1:F(x0)F(x0),即函数在一点的右极限等于该点的函数值。 …...
解决 edge 浏览器开发者工具出不来的问题
文章目录 猜测原因问题现象尝试过程最终解决办法C盘爆满解决经过(拆东墙补西墙) 猜测原因 windows 系统更新导致电脑管家C盘迁移导致(我C盘爆满了,每天提醒看着膈应,想着清理一下) 问题现象 按F12 和 右键…...

嵌入式算法——傅里叶变换算法
文章引注 https://mp.weixin.qq.com/s/5VIpNWci9YLY3m4gcYd6-w 摘要 傅里叶变换的核心在于,“任何连续周期信号可以由一组适当的正弦曲线组合而成”,在这个基础上对信号的中特定频率的正弦波进行分解或者重组,基于频率方面分析波形。 1、傅…...

让数据“动”起来:Python动态图表制作详解
在读技术博客的过程中,我们会发现那些能够把知识、成果讲透的博主很多都会做动态图表。他们的图是怎么做的?难度大吗?这篇文章就介绍了 Python 中一种简单的动态图表制作方法。 数据暴增的年代,数据科学家、分析师在被要求对数据有…...
Python获取网络适配器接口的类型、状态IPv4和IPv6地址
参考CSDN博主「Kwoky」的https://blog.csdn.net/Kwoky/article/details/84858997的简介: psutil是一个跨平台库(http://pythonhosted.org/psutil/)能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要用来…...

无敌了!Redis进军磁盘存储!
在高手林立的数据库江湖,Redis就像一个刺客,或许不如经典数据库存在感强,但因其高性能的特质而在群英榜中独占一席。 作为缓存的首选内存数据库,Redis最近放出了一个大新闻——将磁盘作为分层存储体系结构的一部分,以…...

中文编程开发语言工具编程实际案例:台球棋牌混合计时计费软件使用的编程构件说明
中文编程开发语言工具编程实际案例:台球棋牌混合计时计费软件使用的编程构件说明 上图说明:该软件可以用于桌球和棋牌同时计时计费,在没有开台的时候,图片是处于等待状态,这使用编程工具中的固定图像构件,在…...

在线客服系统源码 客服系统源码
在线客服系统源码 客服系统源码 框架:Thinkphp5workerman,环境:nginxphp7.3mysql5.6 多商户客服、不限坐席、独立系统--数据存储自己服务器上,支持开启SSL、支持离线对话。 新款在线客服系统全开源无加密:多商户、国…...

抽象轻松java——简易图书馆前置
用Maven写一个垃圾的项目,第一步打开IDEA,点击创建,创建一个Maven <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</versi…...

图书推荐管理系统Python+Django网页界面+协同过滤推荐算法
一、介绍 图书管理与推荐系统。使用Python作为主要开发语言。前端采用HTML、CSS、BootStrap等技术搭建界面结构,后端采用Django作为逻辑处理,通过Ajax等技术实现数据交互通信。在图书推荐方面使用经典的协同过滤算法作为推荐算法模块。主要功能有&#…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...