内容简介
如何使用 py-spy
如何读懂火焰图
遇到的问题
大佬组长透露出几个关键信息:
1. 要排查的是线上正在运行的 Python 程序
2.“凌晨 3 点多的时候可能出现”,表示问题并不是每天都出现的
3. 问题现象是程序卡死,重启后,有可以正常运行
线上服运行在真实环境,使用真实数据长时间运行,这种非必发性的错误通常难以在测试服或灰度服中发现,而且这种错误看日志通常难以判断出现这种问题的真正原因,可能其他地方的代码出现了问题,但没有被处理,导致异常状态一直堆积,一段时间后才出现的问题。
根据上面的关键信息,我开始进行如下思考:
1. 思考是否可以构建「最小实例进行复现呢?」,可以复现就说明找到了问题。
2. 是代码的问题还是其他依赖服务存在问题导致本 Python 程序出现问题?
自己在测试环境运行相同的代码,发现没有任何问题,那是其他依赖的问题?这么多依赖服务,一个个查是不现实的,那只能在代码中加多点日志,然后再放到线上去看了?
其实还有使用更简单的方法去定位错误,那就使用 py-spy
使用 py-spy
py-spy 是一款开源的 Python 程序的抽样分析工具,使用 py-spy 可以很直观的查看 Python 程序的进程堆栈以及不同方法的耗时等,整个监控方式不需要对正在运行的程序做任何处理,即你不要修改程序代码也不需要重启程序。
py-spy 使用 Rust 语言开发,Rust 语言是一门号称 C/C++ 的运行速度、类 JavaScript 写法的语言,简单而言,就是开发效率高运行效率也高。py-spy 基于 Rust 语言提供的强大特性,使得它可以安全的用于生产环境中的 python 程序。
通过 pip 安装 py-spy
pip3 install -i https://pypi.doubanio.com/simple/ py-spy
安装完后就可以使用了,如果你是 windows 用户,需要下载预构建的二进制文件进行安装,细究可参考官方说明(在最后参考一节)。
通过 py-spy help
查看该工具支持的指令,总共就 3 种不同的指令,非常简单。
首先来使用 top 命令,它会生成类似 Unix 系统中 top 命令的效果,它有两种使用方式,分别如下。
# 如果python程序正在运行,直接通过pid进行采样
sudo py-spy top --pid 12345
# OR
# 如果python程序没有运行,可以使用如下命令
sudo py-spy top -- python myprogram.py
因为线上 Python 服务本身就是运行状态,所以直接通过 pid 去查看运行进程中的信息,这些信息会依据 py-spy 的采样实时更新。
从上图可以看出,top 命令会显示出当前 Python 进程中 GIL 锁的使用率、活跃线程率、线程数等总体信息,此外还会列出程序中不同方法的占用时间,其中的信息包含了使用的第三方库所占用的时间。
此外,还可以让 py-spy 生成火焰图(flame graph),通过火焰图可以更直观的判断出程序的性能情况。
py-spy 生成火焰图只需使用 record 命令则可,与 top 命令类似,同样有两种使用方式,如下。
py-spy record -o profile.svg --pid 12345
# OR
py-spy record -o profile.svg -- python myprogram.py
-o 参数用于指定火焰图生成的路径。
如果你不清楚怎么看火焰图,不用紧张,后面会介绍火焰图的使用方法。
如果你的程序突然卡死了,你又不清楚它为何会卡死,此时就可以通过 py-spy 的 dump 命令来查看当前程序的调用堆栈,通过调用堆栈来判断 Python 程序挂在何处。
dump 命令只能用于正在运行的 Python 程序。
py-spy dump --pid 12345
从图中可以很清晰的看出当前 Python 程序中所有活跃线程的调用栈。
加多 --locals 参数可以将每个堆栈帧关联的局部变量也打印出来,如下图。
py-spy 的简单用法就介绍完了。
读懂火焰图
火焰图通常是 svg 图片,可以直接通过 Chrome 浏览器打开。
py-spy 生成的火焰图其火焰是向下的,而有些工具生成的火焰图其火焰是向上,样式不同,但没有什么本质区别。
看到刚刚 py-spy 生成的火焰图。
火焰图的 y 轴表示程序的调用栈,每一层都是一个函数,调用栈越深,火焰就越高,最底部就是当前正在执行的函数,上方都是它的父函数。
火焰图 x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,表示它被抽样程序抽到的次数越多,也就表示该方法的执行时间较长。
需要注意,火焰图 x 轴不代表时间,而是所有调用栈合并后,按字母顺序排列而成。
此外,火焰图的颜色没有特殊含义。
火焰图是可以互动的。
1. 鼠标悬浮
当鼠标悬浮在火焰的某一层,火焰图都会显示出当前层对应的完整函数名、抽样抽中的次数、占据总抽样次数的百分比。
2. 可点击放大查看
可以点击火焰的某一层,火焰图会水平放大,该层会占满 x 轴,从而显示出该层的详细信息。
3. 可以搜索
点击火焰图中的 Search 会显示一个搜索框,用户可以输入关键字或正则表达式,所有符合条件的函数名都会高亮显示。
其实 Chromme 浏览器本身就可以生成访问某网站时的性能火焰图。
打开开发者工具 -> 切换到「Performance」 -> 点击「录制」按钮开始记录数据,此时访问 github.com,等网页完全加载后,停止录制,此时,开发者工具就会显示出一个时间轴,而它的下方就是一个火焰图。通过这个火焰图可以详细的分析当前页面的性能。
与传统的火焰图不同,x 轴是时间轴,而不是抽样次数。
参考
1.py-spy github:https://github.com/benfred/py-spy
2. 如何读懂火焰图?:https://www.ruanyifeng.com/blog/2017/09/flame-graph.html