Laravel 高 CPU 使用率:连 Hello World 都把一半 CPU 花在框架引导上
为什么 Laravel 会占用这么多 CPU?
即使是最简单的 Laravel “hello world” 应用,大部分 CPU 时间也消耗在应用代码之外。通过 OpenResty XRay 进行 Laravel CPU 分析可以发现,Service Provider 的启动和注册才是头号 CPU 消耗者——而不是你的路由处理函数。具体来说:
- 最热 PHP 代码路径 #1(36.4% CPU):
bootProvider—— Laravel 在每次请求时都会启动所有已注册的 Service Provider(Carbon 日期库、Ignition 等)。 - 最热 PHP 代码路径 #2(14.5% CPU):
register—— Service Provider 的注册和解析过程(resolveProvider、DatabaseServiceProvider::register等)同样在每次新请求时执行。 - 最热 PHP 代码路径 #3(12.8% CPU):实际的 “hello world” 响应——只有一小部分 CPU 用在了你自己的代码上。
换句话说,在典型的 Laravel 高 CPU 使用率场景中,框架引导开销占据了主导地位。下面的教程将详细介绍如何使用 OpenResty XRay CPU 火焰图来识别这些热路径,帮助你了解优化精力应该集中在哪里。
如果你正在排查更广泛的 PHP 应用高 CPU 问题,许多相同的分析技术同样适用。
下面的演练展示了我们是如何得出这些结论的——从选择目标 PHP 进程到解读 PHP 层的 CPU 火焰图——以便你在自己的 Laravel 应用上重复同样的分析。
测试环境:一个跑满 CPU 的 Hello World 应用
我们用 PHP 的 Laravel 框架搭建了一个简单的 “hello world” Web 应用。
在这里定义了一个请求处理函数,它会返回一个 “Hello, world” 的响应。
使用 curl 命令访问 Laravel 的 HTTP 接口。响应体确实是 “hello world”。
运行 top 命令来检查目标 PHP 进程的 CPU 使用情况。
这是之前展示过的 PHP “hello world” 服务进程。
为了获得清晰的 CPU 分析数据,我们事先使用客户端压测工具将 CPU 使用率压满到 100%。
运行 ps 命令确认该进程使用的是 Linux 发行版自带的标准 php 二进制可执行文件。
Laravel CPU 分析:三条最热代码路径
接下来,我们使用 OpenResty XRay 来查看 CPU 时间是如何分布在 PHP 进程内部的各个代码路径上的。在 OpenResty XRay Web 控制台中,确认正在监控正确的机器,打开 “Guided Analysis” 页面,选择 “High CPU usage” 作为要诊断的问题类型。
接下来,选择 PHP 应用并选取占用近 100% CPU 的工作进程——与之前在 top 中看到的同一个进程(此处为 PID 2092,CPU 占用 93%)。
OpenResty XRay 自动检测应用类型,可以同时分析多个语言级别,因此保持 PHP 和 C/C++ 同时选中,最长分析时间保持默认的 300 秒。启动后,系统进行多轮分析,交替采样 C 层和 PHP 层的 CPU 火焰图。两轮即可满足本例需求,因此在此停止分析。
OpenResty XRay 随后自动生成了一份分析报告。
报告标记了我们诊断的问题类型:CPU。
这是 CPU 资源消耗最高的 C 代码路径,占用了 96.2% 的 CPU 时间。
第一个 zend_execute 函数用于解释和执行 PHP 操作码。
当服务器收到一个新的 HTTP 请求时,php_cli_server_dispatch_router 函数会被调用来读取和解析请求数据。
main 函数帧表明本演示运行在 PHP CLI 启动的内置 Web 服务器上。生产环境部署在 php-fpm 上时,这一层 C 级别的服务器分派帧会有所不同,但下面的 Laravel 框架层 PHP 热点才是重点关注对象。
展开该条目可以查看完整的 C 层调用路径,从 _start 进程入口点,经过服务器事件循环,一直到 PHP 操作码解释器。
这条热代码路径是由这个 C 语言级别的 CPU 火焰图自动推导出来的。
下面是对当前问题更详细的解释和建议。
其中提到了我们之前看到的 zend_execute 函数。
现在来看 PHP 层的结果。最热 PHP 代码路径 #1 单独就消耗了 36.4% 的 CPU 时间。
bootProvider 函数是 Laravel 框架的一部分,该函数负责启动应用注册的 Service Provider。
完整路径显示请求从 public/index.php 和 HTTP 内核进入,然后通过 array_walk 遍历所有已注册的 Provider,展开到 Service Provider 的启动过程。
报告还包含对该代码路径的自动生成解释:bootProvider 启动应用注册的每个 Service Provider,而 Service Provider 是 Laravel 应用配置的核心位置。
放大 PHP 层 CPU 火焰图,可以看到 bootProvider 帧以及其下方正在启动的各个 Service Provider。
Laravel 的 ServiceProvider 程序中,ServiceProvider::boot 方法用于为 Carbon 日期库注册宏和配置。相应的 boot 方法用于初始化时区等设置。
IgnitionServiceProvider::boot 方法负责启动所有的 Service Provider。
再来看第二热 PHP 代码路径 #2,它消耗了 14.5% 的 CPU 时间。
这个 register 函数在应用引导过程中运行,负责解析和注册 Service Provider。由于 Laravel 在每次请求时都会创建新的应用实例(除非使用 Laravel Octane 等常驻内存方案),这一开销会反复产生。
完整路径与上面的启动路径类似:请求从 public/index.php 和 HTTP 内核进入,然后深入到 registerConfiguredProviders。
自动生成的解释分解了同样的调用序列,从 index.php 中的应用入口点开始。
在放大的 PHP 层 CPU 火焰图中,Application::register 帧在周围的引导帧中被高亮显示。
resolveProvider 是 Laravel 框架中的一个方法,用于解析和注册 Service Provider。
DatabaseServiceProvider::register 方法在 Laravel 中负责向服务容器注册数据库服务及其相关组件。
第三热的代码路径消耗了 12.8% 的 CPU 时间。
其调用链经过 Laravel 的路由管道——Router::dispatch、中间件栈和 ControllerDispatcher——最终到达控制器。
这就是实际实现 “hello world” 响应的路径:我们自己的处理函数代码,加上围绕它的路由和响应机制。
注意,#1 和 #2 路径都属于同一个请求级别的引导过程:一个负责启动 Service Provider,另一个负责注册它们。两者合计占了超过一半的 CPU 时间——还未执行任何应用逻辑。
作为参考,这里提供了 Laravel “hello world” 应用与等效 OpenResty 处理函数的吞吐量对比:371 请求/秒 vs 28,000 请求/秒——大约 75 倍的差距。这一对比并非完全对等,因为 Laravel 是一个全栈框架,而 OpenResty 的每请求抽象层要轻量得多,但它说明了上面测量到的框架开销在实际中的代价。如果你的 Laravel 应用还存在高内存消耗问题,OpenResty XRay 同样可以进行分析。
自动 CPU 使用率分析与报告
OpenResty XRay 还可以自动监控在线进程,无需任何手动步骤。“Insights” 页面收集每个应用的日报和周报——包含上述相同的 CPU 分析结果和热代码路径分解——因此日常运行中无需使用 “Guided Analysis”。引导式分析在开发阶段和按需深入分析(如本教程)时仍然很实用。
常见问题:Laravel 高 CPU 使用率
Laravel 的 Service Provider 每次请求都会执行吗?
会。在标准的 Laravel 部署中,每次请求都会创建一个新的应用实例,因此所有 Service Provider 每次都会被注册和启动。在上面的分析中,register(14.5% CPU)和 bootProvider(36.4% CPU)都是逐请求执行的——两者合计超过一半的 CPU,而这些都发生在你的路由逻辑运行之前。这种逐请求的引导过程正是 Laravel 高 CPU 使用率场景中的主导开销。
Laravel Octane 能降低这种 CPU 开销吗?
本文测到的高开销来自每次请求都重复进行 Service Provider 的注册和启动。像 Laravel Octane 这样的常驻内存方案会让应用实例常驻内存,而不是每请求重建,因此这部分引导工作不会被反复执行。如果你的 Laravel 高 CPU 使用率主要由 register 和 bootProvider 路径主导,这正是此类方案要消除的开销。
如何定位 Laravel 应用中最热的代码路径?
使用 OpenResty XRay 的引导式分析剖析运行中的 PHP 进程。它会同时生成 C 层(zend_execute 和 PHP 虚拟机)和 PHP 层(Laravel 框架函数)的 CPU 火焰图,并按 CPU 时间占比对最热的路径排序——本例中为 bootProvider(36.4%)、register(14.5%)和路由响应(12.8%)。这样就能明确看出是哪些框架函数在主导 CPU,而不必靠猜测。
处理 hello world 响应时 OpenResty 比 Laravel 快多少?
在上面的吞吐量对比中,这个 Laravel “hello world” 应用为 371 请求/秒,而等效的 OpenResty 处理函数约为 28,000 请求/秒——大约 75 倍的差距。这一对比并非完全对等,因为 Laravel 是全栈框架,而 OpenResty 每请求的抽象层要轻量得多,但它说明了框架引导开销在实际中的代价。
关于 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、LuaJIT、GDB、SystemTap、LLVM、Perl 等,并编写过 60 多个开源软件库。
关注我们
如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:
翻译
我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!

























































