硬核!使用 eBPF kprobe 高性能解码 HTTP2 压缩头
HTTP2/gRPC 的协议头部使用 HPACK 算法压缩,使得难以从内核系统调用(eBPF kprobe)中获取真实头部字段,因此现有的解决方案通常依赖 eBPF uprobe。本文介绍 DeepFlow 6.4 中基于 eBPF kprobe 的 HTTP2 压缩头高性能解码能力。
01
关于 HPACK
HTTP2 协议头使用了 HPACK 算法进行压缩,以降低头部字段的带宽消耗。如下图所示,HTTP2 的通信双方会向对方共享自己的压缩字典,该字典由两部分组成:编号 1-61 的静态字典(Static table)和编号大于 61 的动态字典(Dynamic table)。在 HTTP2 消息发送之前,发送方会将头部字段中的 Key 或 Key+Value 使用字典中的数字编码替代。当通信中的某一方认为某个不在字典中的头部也值得压缩时,会在发送消息中告知对端向字典中新增表项。除此之外,对于字符串字段,HPACK 算法中规定使用 Huffman 编码算法对字符串进行压缩,也能有效降低长字符串字段的带宽占用。HPACK 的压缩效果显著,例如 Cloudflare 在一篇文章中表示 HPACK 能够对 HTTP2 头部有 3~4 倍的压缩效果。
02
使用 eBPF uprobe 解码
从上图中可以看到,如果直接使用 eBPF kprobe hook 系统调用,得到的实际上是图中最右侧的压缩数据。此时除了可以借助静态字典解码一部分内容以外,大部分业务字段,特别是和追踪相关的 TraceID、SpanID、X-Request-ID 等都无法稳定获取。
因此,无论是 DeepFlow 还是 Pixie 等其他 eBPF 可观测性项目,通常都使用 uprobe 来获取压缩前的头部字段。这种常规的解决方案本文就不再赘述了,大家也可阅读 Observing HTTP/2 Traffic is Hard, but eBPF Can Help (by Yaxiong Zhao) 来了解更多信息。
但是,相比 eBPF kprobe,uprobe 的资源开销更高,而且需要适配不同的语言,因此我们收到了一些通过 kprobe 解码的需求,例如腾讯游戏在 DeepFlow 的落地中就面临了此问题(参见:消灭盲点!腾讯游戏真·全栈观测实践)。
03
使用 eBPF kprobe 解码
安排!DeepFlow 6.4 新增了通过 kprobe 解码 HTTP2/gRPC 压缩头的能力。deepflow-agent 通过自动学习通信双方的压缩字典,能够准确的对压缩头部进行还原。于是,即使不开启 uprobe,调用日志中也能看到所有 DeepFlow 需要的字段信息了:
不仅如此,DeepFlow 6.4 也支持了 RedHat/CentOS 3.10 内核下的 eBPF 能力,欢迎在低版本内核下享用基于 eBPF kprobe 的 HPACK 解码。
不仅如此 x2,除了 eBPF kprobe 以外,对于通过 cBPF 采集到的流量数据,DeepFlow 6.4 也支持了对压缩头的解码,因此即使你的内核版本更低,同样也能享用到此项特性。
这里我们也说明一下此项特性的两点限制:
- 对于 deepflow-agent 启动之前就已经存在的 HTTP2 长连接,已存在的动态字典表项无法解码(但新增的动态字典表项无此限制)
- 当使用 cBPF 时,由于网络中可能存在丢包、重传、乱序等因素,因此对压缩头不的还原可能存在误差(但 eBPF kprobe 无此限制),此项限制我们会在未来版本中逐步消除
04
性能压测
读者看到这里,一定会对「自动学习」、「还原」这类操作产生性能上的担忧,它们会使得 deepflow-agent 占用更多的 CPU、内存资源吗?作为一个金融企业级产品,DeepFlow 在实现此特性时经过了一系列硬核的性能优化和严格的性能压测,本节中我们将会对比关闭动态字典还原、开启动态字典还原两种场景,评估压缩头还原的资源开销。
版本 | 测试场景 | TPS | Agent CPU | Agent MEM |
---|---|---|---|---|
6.3 | 关闭动态字典 | 7400 | 22.5% | 942.8 MB |
6.4 | 开启动态字典(kprobe + cBPF) | 7400 | 16.3% | 672.6 MB |
6.4 | 开启动态字典(kprobe + cBPF) | 43000 | 90.9% | 602.2 MB |
是的,你没有看错,功能更硬核了,性能也更硬核了。在 DeepFlow 6.4 开启动态字典压缩头还原的情况下,CPU、内存开销比 6.3 降低了 30%。并且,当 TPS 从 7,400 增加到 43,000 时,内存消耗没有增长。
此时不得不再次秀出本文的题图:
05
什么是 DeepFlow
DeepFlow 是云杉网络开发的一款可观测性产品,旨在为复杂的云基础设施及云原生应用提供深度可观测性。DeepFlow 基于 eBPF 实现了应用性能指标、分布式追踪、持续性能剖析等观测信号的零侵扰(Zero Code)采集,并结合智能标签(SmartEncoding)技术实现了所有观测信号的全栈(Full Stack)关联和高效存取。使用 DeepFlow,可以让云原生应用自动具有深度可观测性,从而消除开发者不断插桩的沉重负担,并为 DevOps/SRE 团队提供从代码到基础设施的监控及诊断能力。
GitHub 地址:https://github.com/deepflowio/deepflow
访问 DeepFlow Demo,体验零插桩、全覆盖、全关联的可观测性。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
记一次 Rust 内存泄漏排查之旅 | 经验总结篇
在某次持续压测过程中,我们发现 GreptimeDB 的 Frontend 节点内存即使在请求量平稳的阶段也在持续上涨,直至被 OOM kill。我们判断 Frontend 应该是有内存泄漏了,于是开启了排查内存泄漏之旅。 Heap Profiling 大型项目几乎不可能只通过看代码就能找到内存泄漏的地方。所以我们首先要对程序的内存用量做统计分析。幸运的是,GreptimeDB 使用的 jemalloc 自带 heap profiling,我们也支持了导出 jemalloc 的 profile dump 文件。于是我们在 GreptimeDB 的 Frontend 节点内存达到 300MB 和 800MB 时,分别 dump 出了其内存 profile 文件,再用 jemalloc 自带的 jeprof 分析两者内存差异(--base 参数),最后用火焰图显示出来: 显然图片中间那一大长块就是不断增长的 500MB 内存占用了。仔细观察,居然有 thread 相关的 stack trace。难道是创建了太多线程?简单用 ps -T -p 命令看了几次 Frontend 节点的进程,线程...
- 下一篇
ByConity 替换 ClickHouse 构建 OLAP 数据平台,资源成本大幅降低
作者|程伟,MetaAPP 大数据研发工程师 GitHub |https://github.com/ByConity/ByConity ByConity 是字节跳动开源的云原生数据仓库,在满足数仓用户对资源弹性扩缩容,读写分离,资源隔离,数据强一致性等多种需求的同时,并提供优异的查询,写入性能。 MetaApp 是国内领先的游戏开发与运营商,专注移动端信息高效分发,致力于构建面向全年龄段的虚拟世界。截至 2023 年,MetaApp 注册用户已超 2 亿,联运合作 20 万款游戏,累计分发量过 10 亿。 MetaApp 在 ByConity 开源早期便保持关注,是最早进行测试并在生产环境上线的用户之一。抱着了解开源数仓项目能力的想法,MetaApp 大数据研发团队对 ByConity 进行了初步测试。其存算分离的架构、优秀的性能,尤其在日志分析场景中,对于大规模数据复杂查询的支持,吸引 MetaApp 对 ByConity 进行了深入测试,最终在生产环境全量替换 ClickHouse,使资源成本降低超 50%。 本文将主要介绍 MetaApp 数据分析平台的功能,业务场景中遇到的问题...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启