参数调优为什么要采样_程序员精进之路:性能调优利器--火焰图

本文主要分享火焰图使用技巧,介绍 systemtap 的原理机制,如何使用火焰图快速定位性能问题原因,同时加深对 systemtap 的理解。

让我们回想一下,曾经作为编程新手的我们是如何调优程序的?通常是在没有数据的情况下依靠主观臆断来瞎蒙,稍微有些经验的同学则会对差异代码进行二分或者逐段调试。这种定位问题的方式不仅耗时耗力,而且还不具有通用性,当遇到其他类似的性能问题时,需要重复踩坑、填坑,那么如何避免这种情况呢?

俗语有曰:兵欲善其事必先利其器,个人认为,程序员定位性能问题也需要一件“利器”。 如同医生给病人看病,需要依靠专业的医学工具(比如 X 光片、听诊器等)进行诊断,最后依据医学工具的检验结果快速精准的定位出病因所在。性能调优工具(比如 perf / gprof 等)之于性能调优就像 X 光之于病人一样,它可以一针见血的指出程序的性能瓶颈。

但是常用的性能调优工具 perf 等,在呈现内容上只能单一的列出调用栈或者非层次化的时间分布,不够直观。这里我推荐大家配合使用火焰图,它将 perf 等工具采集的数据呈现得更为直观。

初识火焰图

火焰图(Flame Graph)是由 Linux 性能优化大师 Brendan Gregg 发明的,和所有其他的 profiling 方法不同的是,火焰图以一个全局的视野来看待时间分布,它从底部往顶部,列出所有可能导致性能瓶颈的调用栈。

925a14d1dbd6b0b524547d2d945886f6.png

火焰图整个图形看起来就像一个跳动的火焰,这就是它名字的由来。

火焰图有以下特征(这里以 on-cpu 火焰图为例):

  • 每一列代表一个调用栈,每一个格子代表一个函数
  • 纵轴展示了栈的深度,按照调用关系从下到上排列。最顶上格子代表采样时,正在占用 cpu 的函数。
  • 横轴的意义是指:火焰图将采集的多个调用栈信息,通过按字母横向排序的方式将众多信息聚合在一起。需要注意的是它并不代表时间。
  • 横轴格子的宽度代表其在采样中出现频率,所以一个格子的宽度越大,说明它是瓶颈原因的可能性就越大。
  • 火焰图格子的颜色是随机的暖色调,方便区分各个调用信息。
  • 其他的采样方式也可以使用火焰图, on-cpu 火焰图横轴是指 cpu 占用时间,off-cpu 火焰图横轴则代表阻塞时间。
  • 采样可以是单线程、多线程、多进程甚至是多 host,进阶用法可以参考附录进阶阅读

火焰图类型

常见的火焰图类型有 On-CPU,Off-CPU,还有 Memory,Hot/Cold,Differential 等等。他们分别适合处理什么样的问题呢?

这里笔者主要使用到的是 On-CPU、Off-CPU 以及 Memory 火焰图,所以这里仅仅对这三种火焰图作比较,也欢迎大家补充和斧正。

5d04a5713b8ab942d825e239f996621d.png

火焰图类型横轴含义纵轴含义解决问题采样方式cpu 火焰图cpu占用时间调用栈找出 cpu 占用高的问题函数;分析代码热路径固定频率采样 cpu 调用栈off-cpu 火焰图阻塞时间调用栈i/o、网络等阻塞场景导致的性能下降;锁竞争、死锁导致的性能下降问题固定频率采样 阻塞事件调用栈内存火焰图内存申请/释放函数调用次数调用栈内存泄露问题;内存占用高的对象/申请内存多的函数;虚拟内存或物理内存泄露问题有四种方式: 跟踪malloc/free;跟踪brk;跟踪mmap;跟踪页错误Hot/Cold 火焰图on-CPU 火焰图和 off-CPU 火焰图结合在一起综合展示调用栈需要结合 cpu 占用以及阻塞分析的场景;off-CPU 火焰图无法直观判断问题的场景on-CPU 火焰图和 off-CPU 火焰图结合

火焰图分析技巧

  1. 纵轴代表调用栈的深度(栈桢数),用于表示函数间调用关系:下面的函数是上面函数的父函数。
  2. 横轴代表调用频次,一个格子的宽度越大,越说明其可能是瓶颈原因。
  3. 不同类型火焰图适合优化的场景不同,比如 on-cpu 火焰图适合分析 cpu 占用高的问题函数,off-cpu 火焰图适合解决阻塞和锁抢占问题。
  4. 无意义的事情:横向先后顺序是为了聚合,跟函数间依赖或调用关系无关;火焰图各种颜色是为方便区分,本身不具有特殊含义
  5. 多练习:进行性能优化有意识的使用火焰图的方式进行性能调优(如果时间充裕)

如何绘制火焰图?

要生成火焰图,必须要有一个顺手的动态追踪工具,如果操作系统是 Linux 的话,那么通常通常是 perf 或者 systemtap 中的一种。其中 perf 相对更常用,多数 Linux 都包含了 perf 这个工具,可以直接使用;SystemTap 则功能更为强大,监控也更为灵活。网上关于如何使用 perf 绘制火焰图的文章非常多而且丰富,所以本文将以 SystemTap 为例。

SystemTap 是动态追踪工具,它通过探针机制,来采集内核或者应用程序的运行信息,从而可以不用修改内核和应用程序的代码,就获得丰富的信息,帮你分析、定位想要排查的问题。SystemTap 定义了一种类似的 DSL 脚本语言,方便用户根据需要自由扩展。不过,不同于动态追踪的鼻祖 DTrace ,SystemTap 并没有常驻内核的运行时,它需要先把脚本编译为内核模块,然后再插入到内核中执行。这也导致 SystemTap 启动比较缓慢,并且依赖于完整的调试符号表。

使用 SystemTap 绘制火焰图的主要流程如下:

  • 安装 SystemTap 以及 操作系统符号调试表
  • 根据自己所需绘制的火焰图类型以及进程类型选择合适的脚本
  • 生成内核模块
  • 运行 SystemTap 或者运行生成的内核模块统计数据
  • 将统计数据转换成火焰图

本文演示步骤将会基于操作系统 Tlinux 2.2

安装 SystemTap 以及 操作系统符号调试表

使用 yum 工具安装 systemtap:

yum install systemtap systemtap-runtime

由于 systemtap 工具依赖于完整的调试符号表,而且生产环境不同机器的内核版本不同(虽然都是Tlinux 2.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-toolkitstapxx,这两个工具集能够覆盖大部分 C 进程、nginx 进程以及 Openresty 进程的性能问题场景。

我们这里需要绘制 off-cpu 火焰图,所以使用 sample-bt-off-cpu 脚本即可

生成内核模块

现在我们有了统计脚本,也安装好了 systemtap,正常来说就可以使用了,但由于 systemtap 是通过生成内核模块的方式统计相关探针的统计数据,而 tlinux 要求所有运行的内核模块需要先到 tlinux 平台签名才可以运行,所以:

故需要先修改 off-cpu 脚本,让其先生成内核模块;之后对该内核模块作签名;最后使用 systemtap 命令手工运行该脚本,统计监控数据

Systemtap 执行流程如下:

086e2c5c425a45b0b0d1983fad8e08d7.png
  • parse:分析脚本语法
  • elaborate:展开脚本 中定义的探针和连接预定义脚本库,分析内核和内核模块的调试信息
  • translate:.将脚本编译成c语言内核模块文件放 在$HOME/xxx.c 缓存起来,避免同一脚本多次编译
  • build:将c语言模块文件编译成.ko的内核模块,也缓存起来。
  • 把模块交给staprun,staprun加载内核模块到内核空间,stapio连接内核模块和用户空间,提供交互IO通道,采集数据。

所以我们这里修改下 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,链接:https://github.com/brendangregg/FlameGraph

命令:

./stackcollapse-stap.pl demo.bt > demo.folded
./flamegraph.pl demo.folded > demo.svg

这样便获得了 off-cpu 火焰图:

b9b9ca74aa68226fc1c46a6b6c6a39ec.png

看图说话

趁热打铁,通过几张火焰图熟悉下如何使用火焰图

图片来自于春哥微博或者个人近期定位的问题

on-cpu 火焰图

Apache APISIX QPS急剧下降问题

74beea8e0450723777440dfbfec57007.png

Apache APISIX 是一个开源国产的高性能 API 网关,之前在进行选型压测时,发现当 Route 匹配不中场景下, QPS 急剧下降,在其 CPU (四十八核)占用率几乎达到100%的情况下只有几千 QPS,通过绘制火焰图发现,其主要耗时在一个 table 插入阶段(lj_cf_table_insert),分析代码发现是该 table 一直没有释放,每次匹配不中路由会插入数据,导致表越来越大,后续插入耗时过长导致 QPS 下降。

off-cpu 火焰图

nginx 互斥锁问题

55093c02e6aa1b0b1d27545af5c1a81d.png

这是一张 nginx 的 off-cpu 火焰图,我们可以很快锁定到 ngx_common_set_cache_fs_size -> ngx_shmtx_lock -> sem_wait 这段逻辑使用到了互斥锁,它让 nginx 进程绝大部分阻塞等待时间花费在获取该锁。

agent 监控上报断点问题

c65285c4d9181852909f2c26d77d67e7.png

这是一张 agent 的 off-cpu 火焰图,它是一个多线程异步事件模型,主线程处理各个消息,多个线程分别负责配置下发或者监控上报的职责。当前问题出现在监控上报性能差,无法在周期(一分钟)内完成监控数据上报,导致监控断点,通过 off-cpu 火焰图我们可以分析出,该上报线程花费了大量的时间使用 curl_easy_perform 接口收发 http 监控数据消息中。

依据火焰图将发送 http 消息的逻辑改为异步非阻塞后,该问题解决。

附录

进阶阅读

  • 谷歌搜索演讲:Blazing Performance with Flame Graphs
  • 演讲 ppt:https://www.slideshare.net/brendangregg/blazing-performance-with-flame-graphs
  • 《SystemTap新手指南》:https://spacewander.gitbooks.io/systemtapbeginnersguide_zh/content/index.html

FAQ

使用 perf 或者 systemtap 的方式采集数据,会对后台服务有性能影响吗?

有,但是很小,可以基本忽略不计。

它们使用系统的探针或者使用一些自定义的动态探针进行数据采集,第一对代码无侵入性,它既不需要停止服务,也不需要修改应用程序的代码;第二,它们是以内核模块/内核原生的方式跟踪用户态和内核态的所有事件,并通过一系列优化措施,进行采样统计,对目标服务性能影响极小,大概在5%左右或者更低的性能损耗。相较于将进程运行在沙箱的 valgrind 工具或静态调试工具 gdb 来说,动态追踪 perf 或者 systemtap 或者 ebpf 的性能损耗基本可以忽略不计。

目标进程重启后,systemtap 是否需要重新生成内核模块?

不需要。甚至同一个 linux 内核版本下的同一个二进制进程(md5值一致),在安装 kernel 调试符号表后,便可以在生成采集指标的内核模块,并且可以多次使用。

当 linux 内核版本不一致,符号表有变化,需要重新生成内核模块;当目标进程二进制文件重新编译后,也需要重新生成统计用的 systemtap 内核模块。

作者:yousali(厉辉),腾讯 CSIG 后台开发工程师

更多干货尽在腾讯技术,官方QQ交流群已建立,交流讨论可加:957411539。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我是这么理解Vue中的响应式系统的

遇到知识,尤其是复杂的概念,我不能类比的话,我很难接收(所以学习很差...)。在看了大神染陌同学的Vue源码解析后,我想分享一下我所类比的Vue响应式系统,您得先看他的文章(至少看他写的…

图的顺序存储(邻接矩阵存储)【摘录自严长生老师的网站】

图是表达多对多关系的一种数据结构,组成要素为顶点和连接顶点的边。 根据边有无方向可分为有向图和无向图 当边有权重时,升级为有向网和无向网 图在存储时,可采用邻接矩阵,比如下面的无向图(A)和&#xff0…

Neo4j:使隐式关系成为显式和双向关系

最近,我阅读了Michal Bachman关于 Neo4j中双向关系的文章 ,他建议对于某些关系类型,我们对关系的方向不那么感兴趣,因此可以在查询时忽略它。 他使用以下示例显示了Neo Technology和GraphAware之间的合作关系: 两家公…

复旦大学计算机学院博士生王斌,复旦大学计算机科学技术学院博士生刘鹏飞荣获...

计算机科学技术学院发布时间:2017-01-04 小字体 中字体 大字体2016年12月22日,历时七个月选拔的2016年度百度奖学金获奖者揭晓,复旦大学计算机科学技术学院2014级博士生刘鹏飞以其在“自然语言处理与深度学习”上取得的突出成绩,从国内外近百所著名高校数百位竞争者中脱颖而出,…

BZOJ3878: [Ahoi2014Jsoi2014]奇怪的计算器

BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器 Description 【故事背景】 JYY有个奇怪的计算器,有一天这个计算器坏了,JYY希望你能帮助他写一个程序来模拟这个计算器的运算。【问题描述】JYY的计算器可以执行N条预设好的指令。每次JYY向计算器输入一个…

Deno 兼容浏览器具体指的是什么?

Deno 里面有一句描述:"Aims to be browser compatible",可以看到 Deno 的目标是兼容浏览器。那么这里的兼容浏览器到底如何是什么意思呢? 我简单谈谈我的理解吧。 首先这里的兼容性肯定不是 Deno 直接在浏览器端运行。因为 Deno …

判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...

1)实验平台:ALIENTEK NANO STM32F411 V1开发板2)摘自《正点原子STM32F4 开发指南(HAL 库版》关注官方微信号公众号,获取更多资料:正点原子第十六章电容触摸按键实验上一章,我们介绍了 STM32F4 的…

将社交登录添加到Spring MVC Web应用程序:注册和登录

本教程的第一部分描述了如何配置Spring Social 1.1.0和Spring Security 3.2.0,但它留下了两个非常重要的问题尚未解答。 这些问题是: 用户如何创建新用户帐户? 用户如何登录? 现在该弄脏我们的手并回答这些问题了。 我们的示例…

实验五 编写、调试具有多个段的程序

(1)将下面的程序编译、连接,用Debug加载、跟踪,然后回答问题。 ①CPU执行程序,程序返回前,data段的数据为多少? 见下图d 0770:0000 000f结果。 ②CPU执行程序,程序返回前&#xff0c…

手机工商银行怎么转账_工商银行信用卡要哪些申请条件?想成功办理你需要了解这些!...

工商银行信用卡一直是卡友们热议的对象,也有不少卡友问过小白:工商银行信用卡怎么办理?要哪些条件?要等多长时间?那么今天小白就为大家详细的讲解一下工商银行信用卡申请的各种方法和技巧,希望对大家有帮助…

SQL中字符串截取、连接、替换等函数的用法

一、SQL中SUBSTRING函数的用法1、功能:返回字符、二进制、文本或图像表达式的一部分2、语法:SUBSTRING ( expression, start, length )3、QL 中的 substring 函数是用来抓出一个栏位数据中的其中一部分。这个函数的名称在不同的数据库中不完全一样&#…

数据可视化的基本原理——视觉通道

数据可视化为了达到增强人脑认知的目的,会利用不同的视觉通道对冰冷的数据进行视觉编码。 我们在数据可视化的时候,一方面,展现可视化对象本身的位置、特性,对应的视觉通道类型是定性或者分类,比如汽车在什么地方、汽…

身份验证和授权作为开源解决方案服务

通过实施身份验证和授权(a&a)机制为所有用户数据设计集中式服务。 我将分享我的经验并最终确定解决方案的结论。 该设计包括客户端(Web应用程序)和服务器(A&A中心)。 术语&#xf…

linux测试地址是否能访问_一个小测试能看出孩子注意力是否集中,提前弥补,上小学会很轻松...

文|秘籍君不少家长虽然重视孩子的教育,却总是习惯“临阵磨枪”,具体体现在:孩子在上幼儿园的前一两个月才开始着急,害怕孩子适应不了幼儿园;孩子上了大班才开始重视“幼小衔接”,却不知道,从孩子…

服务器怎么禁止iis静态文件,如何禁止IIS缓存静态文件

禁止IIS缓存静态文件(png、js、html等)背景:IIS为了提高性能,默认情况下会对静态文件js、html、gif、png等做内部缓存,这个缓存是在服务器iis进程的内存中的。IIS这么做在很大程度上可以提高静态文件的访问性能,在正常情况下只要静…

汇编实验五

一、 二、 三、 四、 第一个 反汇编后发现不行 第二个 发现也不行 第三个 发现代码正确 五、 编写代码如下 调试后查看内存,发现数据相加了 六、 编写代码如下 发现逆序存储成功 七、实验总结 对于代码段的使用有了更加深入的了解。 但是对于代码段内存这块还是不懂…

eclipse RTC下载的代码无android sdk

问题现象: 修复过程: 1.无ADT,安装ADT(FQ操作) https://dl-ssl.google.com/android/eclipse/ a图 b图 2.下载android sdk a.下载 3.应用到eclipse中去 转载于:https://www.cnblogs.com/liuyj-vv/p/9299913.html

亚马逊免费使用套餐:在EC2 Linux实例上安装Tomcat 7

Amazon Web Services提供了12个月的免费使用期限,使开发人员可以在云中运行任何他们想要的东西。 免费层包括14个服务,其中Web开发人员最关注EC2服务。 EC2是一项服务,通过停止和启动Windows和/或Linux的虚拟实例来提供可调整大小的虚拟计算。…

笔记:隐式转换规则

学习并背诵全文 原始值 类型UndefinedNullStringBooleanNumber值undefinednull所有字符串true false所有数字/NaN 引用类型 Object的成员叫对象,包括Array,Function,Math,Date,JSON,RegExp等除了原始值…