要定位是哪个 PHP 函数导致了高 CPU 使用率,只需把 OpenResty XRay 挂到已经在运行的 PHP 进程上——不用重新编译,也不用重启。它的引导式分析(Guided Analysis)会为这个线上进程生成一张 CPU 火焰图。在本例中,最热的代码路径是业务函数 processOrders 里的一次 preg_match 调用(经由 Laravel 的 callAction 到达),直接把矛头指向了一个正则表达式,它才是消耗 CPU 的瓶颈。

今天我将再用一个例子,一步一步向您展示如何用 OpenResty XRay 分析 PHP 应用。我们会在一个已经在运行的 PHP 进程中,快速定位最热的代码路径——这些代码路径往往消耗了您应用大部分的 CPU 时间。OpenResty XRay 是真正的非侵入式动态分析工具,无需在目标应用中安装任何特殊模块或插件,无需重新编译目标应用,甚至无需重启已经在运行的进程。

问题:高 CPU 使用率

先运行 top 命令来检查 CPU 使用情况。可以看到,这个 php 进程消耗了整整一个 CPU 核心的 100%。

top 命令显示某个 PHP 进程占满了一个 CPU 核心的 100%

再运行 ps 命令查看这个进程的完整命令行。可以看到,它就是 Linux 发行版自带的标准 PHP 二进制可执行文件。

ps 命令输出,显示该 PHP 进程的完整命令行

定位是哪个 PHP 函数在消耗 CPU

让我们用 OpenResty XRay 来实时检查这个未经修改的进程,看看它到底在忙什么。

打开 OpenResty XRay 的 Web 控制台,确认当前分析的是运行着这个高 CPU PHP 进程的机器(如有需要,可以从机器列表里选择另一台),然后进入 “Guided Analysis” 页面。在问题类型列表中,选择 “High CPU Usage”(高 CPU 使用率)。

OpenResty XRay 引导式分析页面,高亮显示高 CPU 使用率问题类型

接着,把分析对象指向这个 PHP 应用,并选中那个占用 100% CPU 的进程——正是我们刚才在 top 里看到的那个。OpenResty XRay 可以同时在多个语言级别上进行分析,所以我们保持 PHP 和 C/C++ 两个级别都选中,最长分析时间也保留默认的 300 秒。开始分析后,系统会自动连续跑好几轮;跑完头一两轮,数据就足够了,于是我们停止分析,让它生成报告。

OpenResty XRay 为该 PHP 进程自动生成的高 CPU 分析报告

这是现在我们要分析的问题类型:CPU:

报告顶部显示本次诊断的问题类型是 CPU

这是占用 CPU 时间最多的第一号最热 PHP 代码路径,占了 56.2% 的 CPU 时间:

报告中第一号最热 PHP 代码路径,占 56.2% 的 CPU 时间

最热的函数调用是 preg_match。它是正则匹配的 PHP 层面的封装:

代码路径中高亮显示的 preg_match 函数

processOrders 函数属于业务代码:

代码路径中高亮显示的业务函数 processOrders

callAction 是 Laravel 框架中的一个方法,用于调用控制器中的指定动作:

代码路径中高亮显示的 Laravel callAction 方法

将鼠标悬停在 processOrders 函数的绿框上。在提示框中可以看到这个 PHP 源文件的完整路径:

提示框显示 processOrders 的源文件 ProductServiceProvider.php 的完整路径

这行源码的行号是 437:

提示框显示该行源码的行号是 437

复制它的源文件路径:

点击复制图标复制该函数的完整源文件路径

使用 Vim 编辑器打开它的源文件,然后查看该文件中的 PHP 代码。您可以使用任何您喜欢的编辑器:

在终端中用 vim 打开 ProductServiceProvider.php 源文件

按照 OpenResty XRay 的建议,跳转到第 437 行:

vim 中跳转到源码第 437 行,高亮显示该行的 preg_match 调用

可以看到,preg_match 的调用和报告相符。由于这个正则表达式是在循环里被反复匹配的,我们可以把它预编译,从而降低 CPU 开销——这是一个具体、可落地的优化:

PHP 源码第 437 行,processOrders 循环内部的 preg_match 调用

这行源代码位于函数 processOrders 内部:

vim 状态栏确认第 437 行位于 processOrders 函数内部

点击 “More” 查看这条代码路径的细节:

点击 More 链接查看代码路径的更多细节

这条热代码路径是由这个 PHP 语言级别的 CPU 火焰图自动推导出来的,火焰图清晰地展示了进程的 CPU 时间实际花在了哪里:

PHP 语言级别的 CPU 火焰图,展示运行进程中最热的代码路径

下面是对问题更详细的解释和建议。它提到了我们之前看到的 preg_match 函数,并给出了减少不必要的中间件、优化正则表达式(避免回溯、使用非捕获分组、减少贪婪量词)等建议:

报告的 Explanation 与 Suggestions 段,解释 preg_match 根因并给出优化建议

看一下这条占用 CPU 时间最多的 C 代码路径。它占了 34.7% 的 CPU 时间,与 PHP 侧的路径相互印证:

第一号最热 C 代码路径,占 34.7% 的 CPU 时间,最热函数为 pcre2_match_8

pcre2_match_8 函数是 PCRE2 库的一部分:

C 代码路径中高亮显示的 PCRE2 库函数 pcre2_match_8

php_pcre_match_impl 函数内部调用 PCRE2 实现正则匹配功能:

C 代码路径中高亮显示的 php_pcre_match_impl 函数

php_do_pcre_match 用于实现 preg_match 函数。它使用正则表达式对字符串进行匹配:

C 代码路径中高亮显示的 php_do_pcre_match 函数

zend_execute_scripts 函数用于执行 PHP 脚本。显然,这和我们刚刚看的 PHP 热代码路径相似。这从 C 语言级别再次证实了:正则匹配才是真正的 CPU 瓶颈:

C 代码路径中高亮显示的 zend_execute_scripts 函数,用于执行 PHP 脚本

这套 PHP profiling 工作流,也同样用于排查它的姊妹问题——PHP 进程内存占用过高,以及追踪线上环境中的 PHP 异常——始终针对线上、未经修改的进程进行。

全自动分析与报告

OpenResty XRay 也可以自动监控线上进程,并生成分析报告。切换到 “Insights” 页面:

左侧导航栏中高亮显示的 Insights 页面入口

您可以在 “Insights” 页面中找到以日和周为周期的自动报告——这样您甚至都不必自己去跑引导式分析:

OpenResty XRay Insights 页面,展示按日和按周自动生成的分析报告

当然,引导式分析在应用的开发和演示场景中依然很有用:

Insights 页面中展示的每日自动分析报告示例

如果您喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

常见问题

为什么我的 PHP 进程 CPU 占用 100%?

一个 CPU 占用飙到 100% 的 PHP 进程属于 CPU 密集型:它在热代码里空转烧 CPU,而不是在等待 I/O。在本例中,罪魁祸首是 processOrders 函数里一个在循环内被反复匹配的 preg_match 正则表达式。把 OpenResty XRay 挂到线上进程上、读取它的 CPU 火焰图,就能准确看出是哪个函数在烧 CPU,全程不用重新编译或重启任何东西。

怎么定位是哪个 PHP 函数导致高 CPU 使用率?

把 OpenResty XRay 挂到已经在运行的 PHP 进程上,针对 “High CPU Usage”(高 CPU 使用率)启动一次引导式分析。它会实时读取该进程,所以您不需要给应用打桩、重新编译或重启。分析结果是一份报告加一张 CPU 火焰图,它会对最热的 PHP 代码路径排序,并把您直接指向那个该负责的函数、源文件和行号。

preg_match 或正则表达式会导致 PHP 高 CPU 吗?

会。preg_match 跑在 PCRE2 引擎之上,反复匹配一个正则表达式——例如在循环内部——可能会占用大量 CPU 时间。本文中最热的 PHP 路径就是 processOrders 里的 preg_match,而最热的 C 路径(经由 php_do_pcre_matchpcre2_match_8)也印证了这一点。把正则表达式预编译好,让它不必在每次迭代时都重新构建,是一个简单直接的解法。

关于 OpenResty XRay

OpenResty XRay 是一个动态追踪产品,它可以自动分析运行中的应用,以解决性能问题、行为问题和安全漏洞,并提供可行的建议。在底层实现上,OpenResty XRay 由我们的 Y 语言驱动,可以在不同环境下支持多种不同的运行时,如 Stap+、eBPF+、GDB 和 ODB。

关于作者

章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!