透過 Swoole 加速 Laravel 效能
Laravel 的速度瓶頸
雖然 Laravel 非常的強大與優美,但是對於 PHP 這種直譯式腳本語言來說,像 Laravel 這種複雜及龐大的框架會使得速度比起原生的 PHP 還要慢上許多,常見的優化方式有以下幾種:
- 使用 Laravel 提供的指令來做快取優化
php artisan optimize
php artisan config:cache
php artisan route:cache
php artisan optimize
在 Laravel 5.5 中已經列為 deprecated,無實際作用(不需要了)。
-
使用 Opcahce 加速
PHP 在每次執行時都會由 Zend 引擎先編譯成 OpCode。最後 Zend 虛擬機再執行 OpCode。Opcache 的作用就是快取 OpCode,進而減少每次需要重新編譯所花費的時間。 -
拋棄 PHP 5.x 的版本,使用 PHP 7.1 以上的版本,效能差很大!
PHP 本身的速度瓶頸
如果你已經針對你的 Laravel 做了以上的優化,但是速度還是不盡理想,那其實速度瓶頸就是卡在 PHP 本身。PHP 的效能瓶頸在哪?簡單來說有以下幾點:
-
即便你開啟了 Opcache,但是從 PHP 的 Lifecycle 來看還是免不了每一次的請求需要的繁雜步驟,且 PHP
資源在每次請求結束後都會銷毀,每次請求都必須重新初始化所有的動作和流程,無法重複利用資源。
-
I/O 效能瓶頸,Laravel 本身要啟動時需要載入的檔案數量非常的多(看看
composer install
裝了那麼多 package 也知道),每次的文件載入都是 I/O 的消耗。 -
PHP 原生不支援以常駐在系統記憶體的方式執行,如果程式只需要在第一次載入時進行初始化,之後便常駐在記憶體當中,那接下來每次的請求就能夠省掉非常大量的資源(像是 node.js 那樣的啟動方式)
當你的 PHP 程式能夠以常駐的方式來執行時,就能夠實現更多原生 PHP 所無法達到的應用,相關的說明可以參照之前介紹 Swoole 的文章或是官方網站。
將 Laravel 透過 Swoole 來執行
這樣的 Package 在之前已經有人做過,但可惜不是不夠完整就是長期缺乏維護,所以我以 Swoole Taiwan 社群的名義從 github 其中一個覺得品質還不錯的專案 fork 出來進行維護開發:Laravel Swoole
安裝方式
以下提供簡略版的安裝步驟,詳細流程與設定請參照:Laravel Swoole
- 透過 composer 進行安裝
composer require swooletw/laravel-swoole
- 設定 Service Provider
[
'providers' => [
SwooleTW\Http\LaravelServiceProvider::class,
],
]
- 執行 Swoole Server
php artisan swoole:http start
效能評測
本評測以完全乾淨的 Lumen 5.5 搭配這個 Pakcage 和原本 Nginx + FPM 的方式進行測試比較。
測試環境為
MacBook Air 13, 2015
,PHP 7.1
- Nginx with FPM
Running 10s test @ http://lumen.app:9999
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.14s 191.03ms 1.40s 90.31%
Req/Sec 22.65 10.65 50.00 65.31%
815 requests in 10.07s, 223.65KB read
Requests/sec: 80.93
Transfer/sec: 22.21KB
- Swoole HTTP Server
Running 10s test @ http://127.0.0.1:1215
4 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 11.58ms 4.74ms 68.73ms 81.63%
Req/Sec 2.19k 357.43 2.90k 69.50%
87879 requests in 10.08s, 15.67MB read
Requests/sec: 8717.00
Transfer/sec: 1.55MB
結論
從以上的評測結果可以發現加速效果非常的顯著,但是當使用這樣的方式來運行 Laravel 時你必須非常了解 Swoole 和 Laravel 的架構和 Lifecycle,才不會寫出讓你有意外結果的程式和 bug。
測試環境中完全撇除
資料庫
,網路
等 I/O 的應用才能有那麼顯著的效果,實際專案中若有使用大量的 I/O 操作需搭配更進階的異步、Coroutine 等方式來避免同步阻塞的時間消耗。