文章采集调用(本文的原理机制,如何使用火焰图快速定位性能问题)
优采云 发布时间: 2022-01-19 03:00文章采集调用(本文的原理机制,如何使用火焰图快速定位性能问题)
本文主要分享使用火焰图的技巧,介绍systemtap的原理和机制,如何使用火焰图快速定位性能问题的原因,加深对systemtap的理解。
让我们回想一下,作为编程新手,我们是如何调整程序的?通常依靠没有数据的主观假设,稍有经验的同学会分两块或一卷调试差异代码。这种定位问题的方法不仅费时费力,而且不具有普遍性。在遇到其他类似的性能问题时,需要反复踩坑填坑,那么如何避免这种情况呢?
有句话叫:兵欲行善,必先利其器。个人认为,程序员也需要一把“利器”来定位性能问题。就像医生看病人一样,需要依靠专业的医疗工具(如X光片、听诊器等)进行诊断,最终根据患者的检测结果快速准确地定位病因。医疗工具。性能调优工具(如 perf / gprof 等)用于性能调优,就像 X 射线用于患者一样。他们可以查明程序的性能瓶颈。
但是,常用的性能调优工具perf等只能在单个显示中列出调用堆栈或非分层时间分布,不够直观。这里推荐大家一起使用火焰图,更直观的呈现perf采集等工具的数据。
初识火焰图
火焰图(Flame Graph)是由 Linux 性能优化大师 Brendan Gregg 发明的。与所有其他分析方法不同,Flame Graph 从全局角度看待时间分布。它从底部到顶部列出了所有可能的原因 性能瓶颈的调用堆栈。
火焰图的整个图看起来像一个跳动的火焰,这就是它的名字的由来。
火焰图有以下特点(这里以on-cpu火焰图为例):
火焰图类型
常见的火焰图类型有 On-CPU、Off-CPU 以及 Memory、Hot/Cold、Differential 等。它们适合什么样的问题?
这里笔者主要使用了On-CPU、Off-CPU和Memory火焰图,所以这里只是对这三个火焰图进行对比,欢迎大家补充指正。
火焰图分析技巧的纵轴代表调用栈的深度(栈帧数),用来表示函数之间的调用关系:下面的函数是上面函数的父函数。横轴代表调用频率。网格的宽度越大,就越有可能成为瓶颈。不同类型的火焰图适用于不同的优化场景。例如,on-cpu 火焰图适用于分析 CPU 使用率较高的问题函数,而 off-cpu 火焰图适用于解决阻塞和锁抢占问题。无意义的东西:横序是为了聚合,与函数之间的依赖或调用关系无关;火焰图的各种颜色是为了方便区分,本身并无特殊含义。更多实践:进行性能优化,自觉使用火焰图法。如何绘制火焰图以进行性能调整(如果有时间)?
要生成火焰图,您必须有一个方便的动态跟踪工具,如果操作系统是 Linux,通常是 perf 或 systemtap 之一。其中,perf相对来说比较常用。大部分Linux系统都收录perf,可以直接使用;SystemTap 在监控方面更强大、更灵活。关于如何使用perf绘制火焰图,网上有很多文章,所以本文将以SystemTap为例。
SystemTap 是一个动态跟踪工具。它利用探针机制来采集内核或应用程序的运行信息,使您无需修改内核和应用程序的代码即可获得丰富的信息,帮助您分析和定位所需的故障排除问题。SystemTap 定义了类似的 DSL 脚本语言,方便用户根据需要自由扩展。但是,与动态跟踪的鼻祖 DTrace 不同,SystemTap 没有驻留的内核运行时。它需要先将脚本编译成内核模块,然后插入内核执行。这也会导致 SystemTap 启动缓慢并依赖于完整的调试符号表。
使用SystemTap绘制火焰图的主要流程如下:
本文的演示步骤将基于操作系统Tlinux 2.2
安装 SystemTap 和 OS 符号调试表
使用 yum 工具安装 systemtap:
yum install systemtap systemtap-runtime
由于systemtap工具依赖于完整的调试符号表,而且生产环境中不同机器的内核版本不同(虽然都是Tlinux2.2版本,但是内核版本之后的次要版本不同,可以通过 uname -a 命令查看)) 所以我们还需要安装 kernel-debuginfo 包和 kernel-devel 包。我在这里安装了这两个依赖包。
kernel-devel-3.10.107-1-tlinux2-0046.x86_64
kernel-debuginfo-3.10.107-1-tlinux2-0046.x86_64
根据需要绘制的火焰图类型和工艺类型选择合适的脚本
使用 SystemTap 统计相关数据,往往需要根据其语法编写脚本,有一定的门槛。好在github上的agentzh开源了他常用的两套SystemTap脚本:openresty-systemtap-toolkit和stapxx,这两套工具集可以覆盖C进程、nginx进程和Openresty进程的大部分性能问题场景。
我们这里需要绘制off-cpu火焰图,所以使用sample-bt-off-cpu脚本
生成内核模块
现在我们已经安装了统计脚本和systemtap,可以正常使用了,但是由于systemtap是通过生成内核模块来统计相关探针的统计信息,而tlinux要求所有运行的内核模块首先到达tlinux平台签名才能运行,所以:
所以需要先修改off-cpu脚本生成内核模块;然后签署内核模块;最后使用systemtap命令手动运行脚本统计监控数据
systemtap执行流程如下:
所以我们在这里修改off-cpu stap脚本,让它只完成第四阶段,只生成一个内核模块
// 在 stap 命令后增加 -p4 参数,告诉systemtap,当前只需要执行到第四阶段
open my $in, "|stap -p4 --skip-badvars --all-modules -x $pid -d '$exec_path' --ldd $d_so_args $stap_args -"
or die "Cannot run stap: $!\n";
修改后运行脚本生成内核模块
// -p 8682 是需要监控的进程的进程号
// -t 30 是指会采样30秒
./sample-bt-off-cpu -p 8692 -t 30
生成的内核模块名称为stap_xxxxx.ko。由于读者无需关心内核模块的签名,本章略过。
运行内核模块统计
内核模块签名后,可以使用staprun命令手动运行相关内核模块
命令:
// 注意:签名脚本会将生产的内核模块重命名,需要将名字改回去……(脚本bug)
staprun -x {进程号} {内核模块名} > demo.bt
值得注意的是,被监控的进程必须有一定的systemtap负载才能采集获取相关数据,即采集时也需要有一定的请求量(通常自己构建请求,对过程进行压力测试)
将统计数据转换为火焰图
一旦你有了统计数据 demo.bt,你就可以使用火焰图工具来绘制火焰图
下载FlameGraph,链接:
命令:
./stackcollapse-stap.pl demo.bt > demo.folded
./flamegraph.pl demo.folded > demo.svg
这给出了 off-cpu 火焰图:
看图说话
趁热打铁,通过几张火焰图熟悉火焰图的使用方法
图片来自春歌微博或个人近期定位问题
On-cpu 火焰图 Apache APISIX QPS 急剧下降问题
Apache APISIX是一款开源的国产高性能API网关。在选型和压测过程中发现,当路由匹配不同场景时,QPS急剧下降。当它的CPU(48核)占用率几乎100%,QPS几千,通过绘制火焰图,发现主要时间花在了一个表插入阶段(lj_cf_table_insert)。分析代码发现表还没有释放。每次路由不匹配,就会插入数据,导致表越来越大。后续插入耗时过长,导致 QPS 下降。
off-cpu 火焰图 nginx mutex 问题
这是一个 nginx 的 off-cpu 火焰图。我们可以快速锁定到 ngx_common_set_cache_fs_size -> ngx_shmtx_lock -> sem_wait。这个逻辑使用了互斥锁,这使得 nginx 进程的大部分阻塞等待时间都花在了获取锁上。
代理监控报告断点问题
这是代理的非 CPU 火焰图。它是一个多线程异步事件模型。主线程处理每条消息,多个线程负责配置和传递或监控和报告的职责。目前的问题是监控上报性能差,无法在周期(一分钟)内完成监控数据上报,导致监控断点。通过off-cpu火焰图,我们可以分析出上报线程在使用curl_easy_perform接口收发http监控数据报文时花费了很多时间。