如何定位并修复 HttpCore5 中的 HTTP2 流量控制问题
简介:开篇吹一波阿里云性能测试服务 PTS,PTS 在 2021 年 5 月份已经上线了对 HTTP2 协议的支持(底层依赖 httpclient5),在压测时会通过与服务端协商的结果来决定使用 HTTP1.1 或者 HTTP2 协议。
作者:风起
开篇吹一波阿里云性能测试服务 PTS[1],PTS 在 2021 年 5 月份已经上线了对 HTTP2 协议的支持(底层依赖 httpclient5),在压测时会通过与服务端协商的结果来决定使用 HTTP1.1 或者 HTTP2 协议。
背景
写这篇文章的原因是某天某个客户找过来,问我们是不是不支持 HTTP2,因为他在 XX 云上购买了 2 个域名,其中一个开启了 HTTP2,而在 PTS 压测过程中,支持 HTTP2 的接口总是报错:
起初怀疑是 HTTP2 支持的问题,通过在本地强制使用 HTTP2 协议,访问淘宝主页,发现是没问题的,怀疑是用户在 XX 云上的配置问题,但紧接着通过在本地 Postman、curl 以及压测引擎强制使用 HTTP1.1 协议时都能够正常访问该网页,意识到大概率是 PTS 引擎侧的问题。
通过本地 debug,看到是因为请求 URL 时,客户端窗口大小被调整为大于 2^32 -1 导致的异常。
那正好借这个机会看下这里的窗口大小指的是什么。
HTTP2 流控
提到窗口,就要提到 HTTP2 相比于 HTTP1.1 支持的新特性:流控(Flow Control),其实 HTTP1.1 依赖于传输层 TCP 的滑动窗口一样可以实现流控,那么为什么 HTTP2 要在应用层再实现一个流控呢?原因在于 HTTP2 引入了流和多路复用,通过流控可以达到使多个流协同的效果。
一些流控的基本概念:
- 流控是针对连接而言的,不是针对端到端的,而是在两端中的每一跳;主要指有代理的情况下,代理与两端都存在流控
- 流控是基于WINDOW_UPDATE 帧的,接收者可以通过流控控制发送者的速度
- 流控既可以作用于 stream 也可以作用于 connection
- 对于连接与所有新开启的流而言,流控窗口大小默认都是 65535,且最大值为 2^32 - 1
- 流控无法禁用
为了便于理解,先简单列一下 HTTP2 帧的类型:
- DATA:携带请求或响应中的数据
- HEADERS:用于新建一个流(请求或响应),包含对应的 Headers
- PRIORITY:用于配置流的优先级
- RST_STREAM:强制结束某个流,仅用于某一端取消流,并不适用于正常流的结束
- SETTINGS:H2 建联的一些配置
- PUSH_PROMISE:服务端推送响应到客户端
- PING:向远端发送一条 PING,远端必须返回该 PING
- GOAWAY:用于某一端将要结束连接
- WINDOW_UPDATE:更新流控窗口大小
- CONTINUATION:如果 headers 过大,单个 HEADERS 帧难以携带,通过该帧发送额外的 headers
接下来,我们重点看下流控相关的帧,主要是 SETTING 与 WINDOW_UPDATE,在连接建立时会通过 SETTINGS 帧来调整对方的窗口大小,之后在传输过程中,窗口大小会随着数据的发送逐渐减小,直到收到对方发送的 WINDOW_UPDATE 帧,从而更新窗口大小。SETTINGS 帧主要包含以下内容:
- SETTINGS_HEADER_TABLE_SIZE:HPACK(一种header压缩算法) header 表的最大长度,默认值 4096
- SETTINGS_ENABLE_PUSH:客户端发向服务端的配置,若设置为 true,客户端将允许服务端推送响应,默认值 true
- SETTINGS_MAX_CONCURRENT_STREAMS:同时打开的 stream 最大数量,通常意味着同一时刻能够同时响应的请求数量,默认无限
- SETTINGS_INITIAL_WINDOW_SIZE:流控的初始窗口大小,默认值 65535
- SETTINGS_MAX_FRAME_SIZE:对端能够接受帧的最大长度,默认值16384
- SETTINGS_MAX_HEADER_LIST_SIZE:对端能够接受的 header 列表最大长度,默认不限制
流控的实现如上所述,每发送一批 DATA 帧,即将窗口大小减小。需要注意的是流控仅针对 DATA 帧。
前面提到流控既可以作用于 stream 又可以作用于 connection,那具体是怎么执行的呢?connection 的流控与 上述 stream 流控逻辑类似,每次发送 DATA 帧,connection 与 stream 窗口都会减小,但不同的是,WINDOW_UPDATE 要么单独作用于 stream,要么单独作用于 connection(streamid 为 0 时,表示作用于 connection)。
问题定位
那么回到开篇的问题,我们以 URL 系统极客 - 专注于操作系统及软件使用教程的技术极客网站 为例,通过在本地做代码 debug 发现,最终抛异常的原因在于接收到 WINDOW_UPDATE 帧后,更新后窗口大小值大于 2^32 - 1 导致抛异常:
而从这里的代码可以看出,524288 是当前窗口大小,而delta是对方告知的 WINDOW_UPDATE 大小,通过分析,发现 524288 这个值不同于默认值 65535,那继续看这个值是什么时间改动的
发现是接收 SETTINGS 指令后,初始化窗口大小时修改的,但这里与 RFC 7540 [2]的描述(connection 窗口大小仅在接收到 WINDOW_UPDATE 后才可能修改)是冲突的:
因此我们断定是 httpcore5 的源代码有 bug,在删除标记的这行代码后,请求可以正常执行了。
遗憾的是在准备给 httpcore5 提 PR 的过程中发现这个 bug 已经在 commit 中被修复了。
参考资料
[1] PTS:
[2] RFC 7540:
RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)
本文为阿里云原创内容,未经允许不得转载。
如何定位并修复 HttpCore5 中的 HTTP2 流量控制问题的更多相关文章
- Java中死锁的定位与修复
死锁应该可以说是并发编程中比较常见的一种情况,可以说如果程序产生了死锁那将会对程序带来致命的影响:所以排查定位.修复死锁至关重要: 我们都知道死锁是由于多个对象或多个线程之间相互需要对方锁持有的锁而又 ...
- 查找并修复Android中的内存泄露—OutOfMemoryError
[编者按]本文作者为来自南非约翰内斯堡的女程序员 Rebecca Franks,Rebecca 热衷于安卓开发,拥有4年安卓应用开发经验.有点完美主义者,喜爱美食. 本文系国内ITOM管理平台 One ...
- [转]教你修复win7中复制粘贴失效的问题
教你修复win7中复制粘贴失效的问题 发布时间:2018-01-17 使用win7系统的时候,我们经常需要对立面的内容进行复制粘贴来引用一些网站的内容,不过最近有网友在使用这个 ...
- QuantLib 金融计算——修复 BatesProcess 中的两个 Bug
QuantLib 金融计算--修复 BatesProcess 中的两个 Bug 我发现了 BatesProcess 中的两个 Bug: 基类 HestonProcess::factors 的返回值取决 ...
- fsck---于检查并且试图修复文件系统中的错误
fsck命令被用于检查并且试图修复文件系统中的错误.当文件系统发生错误四化,可用fsck指令尝试加以修复. -a:自动修复文件系统,不询问任何问题: -A:依照/etc/fstab配置文件的内容,检查 ...
- 如何修复 WordPress 中的 HTTP 错误
如何修复我们会向你介绍,如何在 Linux VPS 上修复 WordPress 中的 HTTP 错误. 下面列出了 WordPress 用户遇到的最常见的 HTTP 错误,我们的建议侧重于如何发现错误 ...
- curl 中关于 CURLINFO_HEADER_SIZE 的 BUG 定位及修复
curl 官方下载页面 CentOS7 默认安装的 curl 版本太低了,需要升级为最新版. 1. 问题描述 对接了一个接口,用来下载 PDF 文件.使用 curl 下载后,文件老是报错无法打开.接口 ...
- 定位现网环境中最耗费CPU的Java线程
参考:JVM性能调优监控工具jps.jstack.jmap.jhat.jstat.hprof使用详解 下面通过一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps. ...
- Android 热修复技术中的CLASS_ISPREVERIFIED问题
一.前言 上一篇博客中,我们通过介绍dex分包原理引出了Android的热补丁技术,而现在我们将解决两个问题. 1. 怎么将修复后的Bug类打包成dex 2. 怎么将外部的dex插入到ClassLoa ...
- 【Python + Selenium断言】之如何获取定位Web页面列表中的数据
如下图所示: 当定位元素时,我想获取指定的某一列的某一行的断言,如图我只想获取jiancha1的值,有同学会说:直接定位不就好了.但是我们知道,列表的数据会时刻变动的,不能靠定死的路径,那该怎么办呢? ...
随机推荐
- .NET开源快速、强大、免费的电子表格组件
前言 今天大姚给大家分享一个.NET开源(MIT License).快速.强大.免费的电子表格组件,支持数据格式.冻结.大纲.公式计算.图表.脚本执行等.兼容 Excel 2007 (.xlsx) 格 ...
- 一个简单的RTMP服务器实现 --- RTMP与FLV
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- linux介绍、安装、shell
1-Linux发展介绍 零 什么是Linux Linux:和我们常见的Windows一样,都是操作系统,但不同的是: Windows: 收费,不开源,主要用于日常办公.游戏.娱乐多一些. Linux: ...
- 恶意软件开发(五)Linux shellcoding
什么是shellcode? Shellcode通常指的是一段用于攻击的机器码(二进制代码),可以被注入到目标计算机中并在其中执行.Shellcode 的目的是利用目标系统的漏洞或弱点,以获取系统控制权 ...
- Cesium渲染模块之FBO与RBO
1. 引言 Cesium是一款三维地球和地图可视化开源JavaScript库,使用WebGL来进行硬件加速图形,使用时不需要任何插件支持,基于Apache2.0许可的开源程序,可以免费用于商业和非商业 ...
- 记录--10个超级实用的Set、Map使用技巧
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 Set是一种类似于数组的数据结构,但是它的值是唯一的,即Set中的每个值只会出现一次.Set对象的实例可以用于存储任何类型的唯一值,从而使 ...
- 快速上手系列:Oracle
一 简介 1.为何需要数据库?存储大量数据,方便检索和访问. 2.文件组成: 数据文件:扩展名是.DBF,用于存储数据库数据的文件,数据库表和数据文件不存在一对一对应关系 控制文件:扩展名是.CTL, ...
- python pyzbar 批量识别二维码
1.安装pyzbar pip install pyzbar 2.代码 import os import cv2 as cv from pyzbar import pyzbar # 目录路径 path ...
- #线段树#洛谷 4340 [SHOI2016]随机序列
题目 分析 可以发现加号和减号会抵消掉,真正有用的答案就是第一段的乘积. 那也就是 \(\sum_{i=1}^nS_i*2*3^{n-i-1}\),其中 \(S_i\) 表示 \(a_1\) 到 \( ...
- #网络流,最小割#洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control
题目 分析 考虑答案求的是最小割,但是最小割的最小边数有点难求, 考虑建立双关键字,其实就是将边权赋值为原边权\(*mx+1\), 其中\(mx\)是一个比较大的数,不需要太大, 这样用网络流做之后对 ...