漫画:如何分析运行中的Python程序?

1,981 阅读6分钟

内容简介

  • 如何使用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轴是时间轴,而不是抽样次数。

参考