透過 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 等方式來避免同步阻塞的時間消耗。