這是一份事后的總結槐壳。在經歷了調優(yōu)過程踩的很多坑之后憾股,我們最終完善并實施了初步的性能測試方案略荡,通過真實的測試數據歸納出了 Laravel 開發(fā)過程中的一些實踐技巧吨拗。
0x00 源起
最近有同事反饋 Laravel 寫的應用程序響應有點慢满哪、20幾個并發(fā)把 CPU 跑滿... 為了解決慢的問題,甚至一部分接口用 nodejs 來寫劝篷。
而我的第一反應是一個流行的框架怎么可能會有這么不堪?一定是使用上哪里出現了問題。為了一探究竟进胯,于是開啟了這次 Laravel 應用性能調優(yōu)之旅辫塌。
0x01 調優(yōu)技巧
這次性能測試方案中用到的優(yōu)化技巧主要基于 Laravel 框架本身及其提供的工具。
- 關閉應用debug
app.debug=false
- 緩存配置信息
php artisan config:cache
- 緩存路由信息
php artisan router:cache
- 類映射加載優(yōu)化
php artisan optimize
- 自動加載優(yōu)化
composer dumpautoload
- 根據需要只加載必要的中間件
- 使用即時編譯器(JIT)哈恰,如:HHVM坟桅、OPcache
- 使用 PHP 7.x
除了以上優(yōu)化技巧之外,還有很多編碼上的實踐可以提升 Laravel 應用性能蕊蝗,在本文中暫時不會做說明仅乓。(也可以關注我的后續(xù)文章)
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. 類映射加載優(yōu)化
php artisan optimize --force
運行以上命令能夠把常用加載的類合并到一個文件中缕棵,通過減少文件的加載來提高運行效率孵班。這個命令會生成 bootstrap/cache/compiled.php
和 bootstrap/cache/services.json
兩個文件涉兽。
通過修改 config/compile.php
文件可以添加要合并的類。
在生產環(huán)境中不需要指定 --force
參數文件也可以自動生成篙程。
php artisan clear-compiled
運行以上命令會清除類映射加載優(yōu)化枷畏,也就是刪除 bootstrap/cache/compiled.php
和 bootstrap/cache/services.json
兩個文件。
5. 自動加載優(yōu)化
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 比起之前的版本在性能上有了極大的提升扇售。
嗯前塔,限于你的真實企業(yè)環(huán)境,這個也許很長時間內改變不了承冰,算我沒說华弓。
0x02 測試方案
我們使用簡單的 Apache ab 命令僅對應用入口文件進行測試,并記錄和分析數據困乒。
- 僅對應用的入口文件 index.php 進行測試寂屏,訪問 “/” 或者 “/index.php” 返回框架的歡迎頁面。更全面的性能測試需要針對應用的更多接口進行測試娜搂。
- 使用 Apache ab 命令迁霎。
ab -t 10 -c 10 {url}
。該命令表示對 url 同時發(fā)起 10 個請求百宇,并持續(xù) 10 秒鐘考廉。命令中具體的參數設置需要根據要測試的服務器性能進行選擇。 - 為了避免機器波動導致的數據錯誤携御,每種測試條件會執(zhí)行多次 ab 命令昌粤,并記錄命令執(zhí)行結果,重點關注每秒處理的請求數及請求響應時間啄刹,分析并剔除異常值涮坐。
- 每次對測試條件進行了調整,需要在瀏覽器上對歡迎頁進行訪問誓军,確保沒有因為測試條件修改而訪問出錯袱讹。如果頁面訪問出錯會導致測試結果錯誤。
服務器環(huán)境說明
所有脫離具體環(huán)境的測試數據都沒有意義昵时,并且只有在相近的條件下才可以進行比較捷雕。
- 這套環(huán)境運行在 Mac 上椒丧,內存 8G,處理器 2.8GHz非区,SSD 硬盤。
- 測試服務器是使用 Homestead 搭建的盹廷。虛擬機配置為單核 CPU征绸、2G 內存。
- 服務器 PHP 版本為 7.1俄占,未特殊說明管怠,則標識開啟了 OPcache。
- 測試的 Laravel 應用程序采用 5.2 版本編寫缸榄。
app\Http\routes.php
中定義了 85 個路由渤弛。 - 測試過程中除了虛擬機、終端及固定的瀏覽器窗口外甚带,沒有會影響機器的程序運行她肯。
以上的數據,大家在自己進行測試時可以參考鹰贵。
0x03 測試過程及數據
1. 未做任何優(yōu)化
1.1 操作
- 按照以下檢查項執(zhí)行相應的操作晴氨。
- 運行
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 結果比較發(fā)現:關閉應用 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 結果比較發(fā)現:開啟配置信息緩存之后菜秦,每秒處理請求數從 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 結果比較發(fā)現:開啟路由信息緩存之后该肴,每秒處理請求數從 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 結果比較發(fā)現:刪除了不必要的中間件之后立哑,每秒處理請求數從 60 左右上升到 90 左右,請求響應時間從 160ms 下降到 110ms 左右姻灶,效果非常明顯刁憋,從 TPS 看,提升了 50%木蹬。
6. 開啟類映射加載優(yōu)化
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 結果比較發(fā)現:做了類映射加載優(yōu)化之后晦譬,每秒處理請求數從 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 結果比較發(fā)現:關閉 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 應用程序優(yōu)化技巧
- 關閉應用debug
app.debug=false
- 緩存配置信息
php artisan config:cache
- 緩存路由信息
php artisan router:cache
- 類映射加載優(yōu)化
php artisan optimize
(包含自動加載優(yōu)化composer dumpautoload
) - 根據需要只加載必要的中間件
- 使用即時編譯器(JIT),如:HHVM萨脑、OPcache
2. 編寫代碼時注意事項
- 路由的具體實現放到控制器中隐轩。
- 不定義重復的路由,尤其注意
resouce
方法渤早。 - 弄清各中間件的作用龙助,刪除不必要的中間件引用。
0x06 下一步
以上的調優(yōu)技巧及編碼注意事項主要針對框架本身,在真正的業(yè)務邏輯編碼中有很多具體的優(yōu)化技巧提鸟,在此沒有討論军援。
后續(xù)的優(yōu)化重點將會放在具體編碼實踐上:
- 使用 Memcached 來存儲會話 config/session.php
- 使用專業(yè)的緩存驅動器
- 數據庫請求優(yōu)化
- 為數據集書寫緩存邏輯
- 前端資源合并 Elixir
0x07 寫在最后
網上看到很多框架性能對比的文章與爭論,也看到很多簡單貼出了數據称勋。這些都不足以窺探真實的情況胸哥,所以有了我們這次的實踐,并在過程中做了詳實的記錄赡鲜。在各位讀者實踐過程中提供參考空厌、比較、反思之用银酬。對于這次實踐有疑問的讀者嘲更,也歡迎提出問題和意見。
不多說了揩瞪,要學習更多技術干貨赋朦,請關注微信公眾號:up2048。
- EOF -