記一次 Laravel 應用效能調優經歷
這是一份事後的總結。在經歷了調優過程踩的很多坑之後,我們最終完善並實施了初步的效能測試方案,通過真實的測試資料歸納出了 Laravel 開發過程中的一些實踐技巧。
0x00 源起
最近有同事反饋 Laravel 寫的應用程式響應有點慢、20幾個併發把 CPU 跑滿... 為了解決慢的問題,甚至一部分介面用 nodejs 來寫。
而我的第一反應是一個流行的框架怎麼可能會有這麼不堪?一定是使用上哪裡出現了問題。為了一探究竟,於是開啟了這次 Laravel 應用效能調優之旅。
0x01 調優技巧
這次效能測試方案中用到的優化技巧主要基於 Laravel 框架本身及其提供的工具。
- 關閉應用debug
app.debug=false
- 快取配置資訊
php artisan config:cache
- 快取路由資訊
php artisan router:cache
- 類對映載入優化
php artisan optimize
- 自動載入優化
composer dumpautoload
- 根據需要只載入必要的中介軟體
- 使用即時編譯器(JIT),如:HHVM、OPcache
- 使用 PHP 7.x
除了以上優化技巧之外,還有很多編碼上的實踐可以提升 Laravel 應用效能,在本文中暫時不會做說明。(也可以關注我的後續文章)
1. 關閉應用 debug
開啟應用根目錄下的 .env 檔案,把 debug 設定為 false。
APP_DEBUG=false
2. 快取配置資訊
php artisan config:cache
執行以上命令可以把 config 資料夾裡所有配置資訊合併到一個 bootstrap/cache/config.php
檔案中,減少執行時載入檔案的數量。
php artisan config:clear
執行以上命令可以清除配置資訊的快取,也就是刪除 bootstrap/cache/config.php
檔案
3. 快取路由資訊
php artisan route:cache
執行以上命令會生成檔案 bootstrap/cache/routes.php
。路由快取可以有效的提高路由器的註冊效率,在大型應用程式中效果越加明顯。
php artisan route:clear
執行以上命令會清除路由快取,也就是刪除 bootstrap/cache/routes.php
檔案。
4. 類對映載入優化
php artisan optimize --force
執行以上命令能夠把常用載入的類合併到一個檔案中,通過減少檔案的載入來提高執行效率。這個命令會生成 bootstrap/cache/compiled.php
和 bootstrap/cache/services.json
兩個檔案。
通過修改 config/compile.php
檔案可以新增要合併的類。
在生產環境中不需要指定 --force
引數檔案也可以自動生成。
php artisan clear-compiled
執行以上命令會清除類對映載入優化,也就是刪除 bootstrap/cache/compiled.php
和 bootstrap/cache/services.json
兩個檔案。
5. 自動載入優化
composer dumpautoload -o
Laravel 應用程式是使用 composer 來構建的。這個命令會把 PSR-0 和 PSR-4 轉換為一個類對映表來提高類的載入速度。
注意:
php artisan optimize --force
命令裡已經做了這個操作。
6. 根據需要只載入必要的中介軟體
Laravel 應用程式內建了並開啟了很多的中介軟體。每一個 Laravel 的請求都會載入相關的中介軟體、產生各種資料。在 app/Http/Kernel.php
中註釋掉不需要的中介軟體(如 session 支援)可以極大的提升效能。
7. 使用即時編譯器
HHVM 和 OPcache 都能輕輕鬆鬆的讓你的應用程式在不用做任何修改的情況下,直接提高 50% 或者更高的效能。
8. 使用 PHP 7.x
只能說 PHP 7.x 比起之前的版本在效能上有了極大的提升。
嗯,限於你的真實企業環境,這個也許很長時間內改變不了,算我沒說。
0x02 測試方案
我們使用簡單的 Apache ab 命令僅對應用入口檔案進行測試,並記錄和分析資料。
- 僅對應用的入口檔案 index.php 進行測試,訪問 “/” 或者 “/index.php” 返回框架的歡迎頁面。更全面的效能測試需要針對應用的更多介面進行測試。
- 使用 Apache ab 命令。
ab -t 10 -c 10 {url}
。該命令表示對 url 同時發起 10 個請求,並持續 10 秒鐘。命令中具體的引數設定需要根據要測試的伺服器效能進行選擇。 - 為了避免機器波動導致的資料錯誤,每種測試條件會執行多次 ab 命令,並記錄命令執行結果,重點關注每秒處理的請求數及請求響應時間,分析並剔除異常值。
- 每次對測試條件進行了調整,需要在瀏覽器上對歡迎頁進行訪問,確保沒有因為測試條件修改而訪問出錯。如果頁面訪問出錯會導致測試結果錯誤。
伺服器環境說明
所有脫離具體環境的測試資料都沒有意義,並且只有在相近的條件下才可以進行比較。
- 這套環境執行在 Mac 上,記憶體 8G,處理器 2.8GHz,SSD 硬碟。
- 測試伺服器是使用 Homestead 搭建的。虛擬機器配置為單核 CPU、2G 記憶體。
- 伺服器 PHP 版本為 7.1,未特殊說明,則標識開啟了 OPcache。
- 測試的 Laravel 應用程式採用 5.2 版本編寫。
app\Http\routes.php
中定義了 85 個路由。 - 測試過程中除了虛擬機器、終端及固定的瀏覽器視窗外,沒有會影響機器的程式執行。
以上的資料,大家在自己進行測試時可以參考。
0x03 測試過程及資料
1. 未做任何優化
1.1 操作
- 按照以下檢查項執行相應的操作。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
基礎檢查項
- .env 檔案中
APP_DEBUG=true
- 不存在
bootstrap/cache/config.php
- 不存在
bootstrap/cache/routes.php
- 不存在
bootstrap/cache/compiled.php
和bootstrap/cache/services.json
-
app/Http/Kernel.php
中開啟了大部分的中介軟體 - 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問
1.2 資料記錄
2. 關閉應用debug
2.1 操作
- 在步驟 1 基礎上修改 .env 檔案中
APP_DEBUG=false
。 - 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
2.2 資料記錄
2.3 對比結果
與步驟 1 結果比較發現:關閉應用 debug 之後,每秒處理請求數從 26-34 上升到 33-35,請求響應時間從 大部分 300ms 以上下降到 290ms 左右,效果不太明顯,但確實有一定的提升。
注意:這部分與應用中的日誌等使用情況有比較大的關聯。
3. 開啟快取配置資訊
3.1 操作
- 在步驟 2 基礎上,執行
php artisan config:cache
,確認生成bootstrap/cache/config.php
。 - 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
3.2 資料記錄
3.3 對比結果
與步驟 2 結果比較發現:開啟配置資訊快取之後,每秒處理請求數從 33-35 上升到 36-38,請求響應時間從 290ms 左右下降到 260ms 左右,效果不太明顯,但確實有一定的提升。
4. 開啟快取路由資訊
4.1 操作
- 在步驟 3 基礎上,執行
php artisan route:cache
,確認生成bootstrap/cache/routes.php
。 - 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
4.2 資料記錄
4.3 對比結果
與步驟 3 結果比較發現:開啟路由資訊快取之後,每秒處理請求數從 36-38 上升到 60 左右,請求響應時間從 260ms 下降到 160ms 左右,效果顯著,從 TPS 看,提升了 70%。
5. 刪除不必要的中介軟體
5.1 操作
- 在步驟 4 基礎上,註釋掉不必要的中介軟體程式碼。
- 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
注意:這次測試中我註釋掉了所有的中介軟體。實際情況中應該儘量只留下必要的中介軟體。
5.2 資料記錄
5.3 對比結果
與步驟 4 結果比較發現:刪除了不必要的中介軟體之後,每秒處理請求數從 60 左右上升到 90 左右,請求響應時間從 160ms 下降到 110ms 左右,效果非常明顯,從 TPS 看,提升了 50%。
6. 開啟類對映載入優化
6.1 操作
- 在步驟 5 基礎上,執行
php artisan optimize --force
,確認生成bootstrap/cache/compiled.php
和bootstrap/cache/services.json
。 - 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
6.2 資料記錄
6.3 對比結果
與步驟 5 結果比較發現:做了類對映載入優化之後,每秒處理請求數從 90 上升到 110,請求響應時間從 110ms 下降到 100ms 以下,效果還是比較明顯的。
7. 關閉 OPcache
7.1 操作
- 在步驟 6 基礎上,關閉 PHP 的 OPcache,並重啟伺服器。通過 phpinfo() 的 Zend OPcache 確認 OPcache 已經關閉。
- 瀏覽器訪問 Laravel 應用程式歡迎頁確保正常訪問。
- 執行
ab -t 10 -c 10 http://myurl.com/index.php
。
7.2 資料記錄
7.3 對比結果
與步驟 6 結果比較發現:關閉 OPcache 之後,每秒處理請求數從 110 下降到 15,請求響應時間從 100ms 以下上升到 650ms 以上。開啟與關閉 OPcache,資料上竟有幾倍的差別。
此後,我重新開啟了 PHP 的 OPcache,資料恢復到步驟 6 水平。
0x04 踩過的坑
1. [LogicException] Unable to prepare route [/] for serialization. Uses Closure.
在執行 php artisan route:cache
命令時報這個錯誤。
原因:路由檔案中處理“/”時使用了閉包的方式。要執行該命令,路由的具體實現不能使用閉包方式。
修改方案:將路由的具體實現放到控制器中來實現。
2. [Exception] Serialization of 'Closure' is not allowed.
在執行 php artisan route:cache
命令時報這個錯誤。
原因:路由檔案中定義了重複的路由。
修改方案:排查路由檔案中的重複路由並修改。尤其要注意 resource
方法很可能導致與其方法重複。
3. [RuntimeException] Invalid filename provided.
在執行 php artisan optimize --force
命名時報這個錯誤。
原因:在載入需要編譯的類時沒有找到相應的檔案。5.2 版本的 vendor/laravel/framework/src/Illuminate/Foundation/Console/Optimize/config.php
中定義了要編譯的檔案路徑,但不知道為什麼 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/ActiveRecords.php
沒有找到,所以報了這個錯誤。
修改方案:暫時註釋掉了以上 config.php 中的 ../ActiveRecords.php
一行。
4. InvalidArgumentException in FileViewFinder.php line 137: View [welcome] not found.
在執行 php artisan config:cache
之後,瀏覽器上訪問 Laravel 應用程式歡迎頁報這個錯誤。
原因:Laravel 應用程式伺服器是通過 Homestead 在虛擬機器上搭建的。而這個命令我是在虛擬機器之外執行的,導致生成的 config.php 中的路徑是本機路徑,而不是虛擬機器上的路徑。所以無法找到檢視檔案。
修改方案:ssh 到虛擬機器內部執行該命令。
0x04 實踐技巧
坑也踩了,測試也做過了。這裡針對這次經歷做個實踐技巧的簡單總結。
1. 有效的 Laravel 應用程式優化技巧
- 關閉應用debug
app.debug=false
- 快取配置資訊
php artisan config:cache
- 快取路由資訊
php artisan router:cache
- 類對映載入優化
php artisan optimize
(包含自動載入優化composer dumpautoload
) - 根據需要只載入必要的中介軟體
- 使用即時編譯器(JIT),如:HHVM、OPcache
2. 編寫程式碼時注意事項
- 路由的具體實現放到控制器中。
- 不定義重複的路由,尤其注意
resouce
方法。 - 弄清各中介軟體的作用,刪除不必要的中介軟體引用。
0x06 下一步
以上的調優技巧及編碼注意事項主要針對框架本身,在真正的業務邏輯編碼中有很多具體的優化技巧,在此沒有討論。
後續的優化重點將會放在具體編碼實踐上:
- 使用 Memcached 來儲存會話 config/session.php
- 使用專業的快取驅動器
- 資料庫請求優化
- 為資料集書寫快取邏輯
- 前端資源合併 Elixir
0x07 寫在最後
網上看到很多框架效能對比的文章與爭論,也看到很多簡單貼出了資料。這些都不足以窺探真實的情況,所以有了我們這次的實踐,並在過程中做了詳實的記錄。在各位讀者實踐過程中提供參考、比較、反思之用。對於這次實踐有疑問的讀者,也歡迎提出問題和意見。
不多說了,要學習更多技術乾貨,請關注微信公眾號:up2048。
- EOF -
推薦閱讀
相關文章
- 記一次效能優化經歷優化
- 記一次我的 MySQL 調優經歷MySql
- 【譯】React 應用效能調優React
- python效能調優的一次記錄Python
- 記一次真實的webpack優化經歷Web優化
- 簡單JVM調優經歷JVM
- MySQL效能調優"經驗"MySql
- 格物致知—機器學習應用效能調優機器學習
- 記一次面試經歷面試
- 大型跨境電商JVM調優經歷JVM
- 記一次使用策略模式優化程式碼的經歷模式優化
- 記一次 Google 面試經歷Go面試
- 記錄一次WhatTheFuck經歷
- java效能調優記錄Java
- 應用調優
- Laravel 模型操作中一次奇妙踩坑經歷Laravel模型
- Java 應用效能調優最強實踐指南!Java
- 記一次翻譯站經歷
- 記一次 jQuery 踩坑經歷jQuery
- 一次效能測試調優總結
- 一次openrestyhttp.lua效能調優之旅RESTHTTP
- 一次效能優化調整過程.優化
- 一次oracle sql調優的經歷(隱士轉換導致索引失效)OracleSQL索引
- Laravel 高併發調優筆記Laravel筆記
- 不斷優化配置,逐步提高效能——我的一次效能測試經歷優化
- 調優 | Apache Hudi應用調優指南Apache
- java效能調優記錄(限流)Java
- ? 記一次前端效能優化前端優化
- 一次資料庫的優化經歷資料庫優化
- 上線清單 —— 20 個 Laravel 應用效能優化項Laravel優化
- 記錄一次微信分享的經歷
- 記一次編譯GCC的經歷編譯GC
- 記一次 CDN 流量被盜刷經歷
- 記一次SQL調優過程SQL
- 一次 JVM 調優的筆記JVM筆記
- 一次非常有趣的 SQL 優化經歷SQL優化
- 一次非常有趣的sql優化經歷SQL優化
- 一次生產事故的優化經歷優化