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. 公司的部落格網站 。也歡迎掃碼關注我們的微信公眾號:
翻譯
我們提供了英文版原文和中譯版(本文)。我們也歡迎讀者提供其他語言的翻譯版本,只要是全文翻譯不帶省略,我們都將會考慮採用,非常感謝!

























































