記一次 Laravel 應用性能調優(yōu)經歷

這是一份事后的總結槐壳。在經歷了調優(yōu)過程踩的很多坑之后憾股,我們最終完善并實施了初步的性能測試方案略荡,通過真實的測試數據歸納出了 Laravel 開發(fā)過程中的一些實踐技巧吨拗。

0x00 源起

最近有同事反饋 Laravel 寫的應用程序響應有點慢满哪、20幾個并發(fā)把 CPU 跑滿... 為了解決慢的問題,甚至一部分接口用 nodejs 來寫劝篷。

而我的第一反應是一個流行的框架怎么可能會有這么不堪?一定是使用上哪里出現了問題。為了一探究竟进胯,于是開啟了這次 Laravel 應用性能調優(yōu)之旅辫塌。

0x01 調優(yōu)技巧

這次性能測試方案中用到的優(yōu)化技巧主要基于 Laravel 框架本身及其提供的工具。

  1. 關閉應用debug app.debug=false
  2. 緩存配置信息 php artisan config:cache
  3. 緩存路由信息 php artisan router:cache
  4. 類映射加載優(yōu)化 php artisan optimize
  5. 自動加載優(yōu)化 composer dumpautoload
  6. 根據需要只加載必要的中間件
  7. 使用即時編譯器(JIT)哈恰,如:HHVM坟桅、OPcache
  8. 使用 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.phpbootstrap/cache/services.json 兩個文件涉兽。

通過修改 config/compile.php 文件可以添加要合并的類。

在生產環(huán)境中不需要指定 --force 參數文件也可以自動生成篙程。

php artisan clear-compiled

運行以上命令會清除類映射加載優(yōu)化枷畏,也就是刪除 bootstrap/cache/compiled.phpbootstrap/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 命令僅對應用入口文件進行測試,并記錄和分析數據困乒。

  1. 僅對應用的入口文件 index.php 進行測試寂屏,訪問 “/” 或者 “/index.php” 返回框架的歡迎頁面。更全面的性能測試需要針對應用的更多接口進行測試娜搂。
  2. 使用 Apache ab 命令迁霎。ab -t 10 -c 10 {url}。該命令表示對 url 同時發(fā)起 10 個請求百宇,并持續(xù) 10 秒鐘考廉。命令中具體的參數設置需要根據要測試的服務器性能進行選擇。
  3. 為了避免機器波動導致的數據錯誤携御,每種測試條件會執(zhí)行多次 ab 命令昌粤,并記錄命令執(zhí)行結果,重點關注每秒處理的請求數及請求響應時間啄刹,分析并剔除異常值涮坐。
  4. 每次對測試條件進行了調整,需要在瀏覽器上對歡迎頁進行訪問誓军,確保沒有因為測試條件修改而訪問出錯袱讹。如果頁面訪問出錯會導致測試結果錯誤。

服務器環(huán)境說明

所有脫離具體環(huán)境的測試數據都沒有意義昵时,并且只有在相近的條件下才可以進行比較捷雕。

  1. 這套環(huán)境運行在 Mac 上椒丧,內存 8G,處理器 2.8GHz非区,SSD 硬盤。
  2. 測試服務器是使用 Homestead 搭建的盹廷。虛擬機配置為單核 CPU征绸、2G 內存。
  3. 服務器 PHP 版本為 7.1俄占,未特殊說明管怠,則標識開啟了 OPcache。
  4. 測試的 Laravel 應用程序采用 5.2 版本編寫缸榄。app\Http\routes.php 中定義了 85 個路由渤弛。
  5. 測試過程中除了虛擬機、終端及固定的瀏覽器窗口外甚带,沒有會影響機器的程序運行她肯。

以上的數據,大家在自己進行測試時可以參考鹰贵。

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.phpbootstrap/cache/services.json
  • app/Http/Kernel.php 中開啟了大部分的中間件
  • 瀏覽器訪問 Laravel 應用程序歡迎頁確保正常訪問

1.2 數據記錄

1-未開啟優(yōu)化

2. 關閉應用debug

2.1 操作

  • 在步驟 1 基礎上修改 .env 文件中 APP_DEBUG=false
  • 瀏覽器訪問 Laravel 應用程序歡迎頁確保正常訪問碉输。
  • 運行 ab -t 10 -c 10 http://myurl.com/index.php籽前。

2.2 數據記錄

2-關閉應用debug

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.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-緩存路由信息

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-刪除不必要的中間件

5.3 對比結果

與步驟 4 結果比較發(fā)現:刪除了不必要的中間件之后立哑,每秒處理請求數從 60 左右上升到 90 左右,請求響應時間從 160ms 下降到 110ms 左右姻灶,效果非常明顯刁憋,從 TPS 看,提升了 50%木蹬。

6. 開啟類映射加載優(yōu)化

6.1 操作

  • 在步驟 5 基礎上至耻,運行 php artisan optimize --force,確認生成 bootstrap/cache/compiled.phpbootstrap/cache/services.json镊叁。
  • 瀏覽器訪問 Laravel 應用程序歡迎頁確保正常訪問尘颓。
  • 運行 ab -t 10 -c 10 http://myurl.com/index.php

6.2 數據記錄

6-類映射加載優(yōu)化

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-關閉了OPcache

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)化技巧

  1. 關閉應用debug app.debug=false
  2. 緩存配置信息 php artisan config:cache
  3. 緩存路由信息 php artisan router:cache
  4. 類映射加載優(yōu)化 php artisan optimize(包含自動加載優(yōu)化 composer dumpautoload
  5. 根據需要只加載必要的中間件
  6. 使用即時編譯器(JIT),如:HHVM萨脑、OPcache

2. 編寫代碼時注意事項

  1. 路由的具體實現放到控制器中隐轩。
  2. 不定義重復的路由,尤其注意 resouce 方法渤早。
  3. 弄清各中間件的作用龙助,刪除不必要的中間件引用。

0x06 下一步

以上的調優(yōu)技巧及編碼注意事項主要針對框架本身,在真正的業(yè)務邏輯編碼中有很多具體的優(yōu)化技巧提鸟,在此沒有討論军援。

后續(xù)的優(yōu)化重點將會放在具體編碼實踐上:

  1. 使用 Memcached 來存儲會話 config/session.php
  2. 使用專業(yè)的緩存驅動器
  3. 數據庫請求優(yōu)化
  4. 為數據集書寫緩存邏輯
  5. 前端資源合并 Elixir

0x07 寫在最后

網上看到很多框架性能對比的文章與爭論,也看到很多簡單貼出了數據称勋。這些都不足以窺探真實的情況胸哥,所以有了我們這次的實踐,并在過程中做了詳實的記錄赡鲜。在各位讀者實踐過程中提供參考空厌、比較、反思之用银酬。對于這次實踐有疑問的讀者嘲更,也歡迎提出問題和意見。

不多說了揩瞪,要學習更多技術干貨赋朦,請關注微信公眾號:up2048。

- EOF -

推薦閱讀

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市妇菱,隨后出現的幾起案子承粤,更是在濱河造成了極大的恐慌,老刑警劉巖闯团,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辛臊,死亡現場離奇詭異,居然都是意外死亡偷俭,警方通過查閱死者的電腦和手機浪讳,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涌萤,“玉大人淹遵,你說我怎么就攤上這事「合” “怎么了透揣?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長川抡。 經常有香客問我辐真,道長须尚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任侍咱,我火速辦了婚禮耐床,結果婚禮上,老公的妹妹穿的比我還像新娘楔脯。我一直安慰自己撩轰,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布昧廷。 她就那樣靜靜地躺著堪嫂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪木柬。 梳的紋絲不亂的頭發(fā)上皆串,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音眉枕,去河邊找鬼恶复。 笑死,一個胖子當著我的面吹牛齐遵,可吹牛的內容都是我干的寂玲。 我是一名探鬼主播塔插,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼梗摇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了想许?” 一聲冷哼從身側響起伶授,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎流纹,沒想到半個月后糜烹,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡漱凝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年疮蹦,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茸炒。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡愕乎,死狀恐怖,靈堂內的尸體忽然破棺而出壁公,到底是詐尸還是另有隱情感论,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布紊册,位于F島的核電站比肄,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜芳绩,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一掀亥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妥色,春花似錦铺浇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吼拥,卻和暖如春倚聚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凿可。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工惑折, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枯跑。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓惨驶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敛助。 傳聞我的和親對象是個殘疾皇子粗卜,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容