PHPの性能はバイトコードキャッシュにより数倍向上するのですが、久しぶりにopcacheをキーワードに検索してみると「それほど効果がない」と誤った評価をしているページもあったので、Opcacheによりどのくらい速くなるか簡単なベンチマークをします。
テスト環境
- CPU – Intel(R) Core(TM) i7-4770S CPU @ 3.10GHz
- メモリ – DDR3 32GB
- OS – Fedora 23 x86_64(4.3.4-300.fc23.x86_64)
- Webサーバー – Fedora 23 httpd パッケージ(httpd-2.4.18-1.fc23.x86_64)
- PHP – Fedora 23 PHP 5.6.17 パッケージ(php-5.6.17-1.fc23.x86_64)
- Opcache – Fedora 23 Opcacheパッケージ(php-opcache-5.6.17-1.fc23.x86_64)
httpdにはサーバー名によって自動的に仮想ホストを切り換える設定がされています。これ以外の変更は特に無く、パッケージ設定以外のチューニング設定を行わないデフォルト設定を利用します。
テストアプリケーション
- FuelPHP 1.7.3 のデフォルトページ
FuelPHPをインストールして最初に表示されるページを利用します。
ベンチマーク
abコマンドを使います。もっと高機能なツールでも良いのですがシンプルイズベストということでabコマンドにします。abコマンドもhttpdサーバーも同じPC上で実行します。Opcache有り/無しで数回実行した結果のうち中間辺りの結果を記載します。
Opcache有り
[yohgaki@dev ~]$ ab -c 100 -n 10000 http://localhost/fuel/public/ This is ApacheBench, Version 2.3 <$Revision: 1706008 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Apache/2.4.18 Server Hostname: localhost Server Port: 80 Document Path: /fuel/public/ Document Length: 28814 bytes Concurrency Level: 100 Time taken for tests: 5.770 seconds Complete requests: 10000 Failed requests: 389 (Connect: 0, Receive: 0, Length: 389, Exceptions: 0) Total transferred: 290459610 bytes HTML transferred: 288139610 bytes Requests per second: 1733.17 [#/sec] (mean) Time per request: 57.698 [ms] (mean) Time per request: 0.577 [ms] (mean, across all concurrent requests) Transfer rate: 49161.74 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 1 Processing: 3 57 9.6 56 89 Waiting: 3 57 9.6 56 89 Total: 5 57 9.6 56 90 Percentage of the requests served within a certain time (ms) 50% 56 66% 59 75% 64 80% 66 90% 71 95% 75 98% 78 99% 80 100% 90 (longest request)
Opcache無し
[yohgaki@dev ~]$ ab -c 100 -n 10000 http://localhost/fuel/public/ This is ApacheBench, Version 2.3 <$Revision: 1706008 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Apache/2.4.18 Server Hostname: localhost Server Port: 80 Document Path: /fuel/public/ Document Length: 28814 bytes Concurrency Level: 100 Time taken for tests: 29.329 seconds Complete requests: 10000 Failed requests: 1042 (Connect: 0, Receive: 0, Length: 1042, Exceptions: 0) Total transferred: 290458831 bytes HTML transferred: 288138831 bytes Requests per second: 340.96 [#/sec] (mean) Time per request: 293.285 [ms] (mean) Time per request: 2.933 [ms] (mean, across all concurrent requests) Transfer rate: 9671.51 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 1 Processing: 20 292 34.7 289 508 Waiting: 19 287 32.9 285 483 Total: 21 292 34.6 289 508 Percentage of the requests served within a certain time (ms) 50% 289 66% 302 75% 311 80% 316 90% 332 95% 348 98% 374 99% 395 100% 508 (longest request)
ベンチマーク結果の評価
バイトコードキャッシュの性能を正しく評価するには幾つかのポイントがあります。
- バイトコードキャッシュはスクリプトのコンパイル結果をキャッシュする
コンパイル結果をキャッシュするので2回目以降のリクエストでないと速くなりません。最近のOpcacheはファイルにキャッシュすることができますが、メモリにキャッシュしているとCLI/CGIの場合は速くなりません。
- Web環境では多数の同時リクエストを想定しなければならない
Webアプリを速くしたい=沢山のアクセスがある、という場合が多いと思います。同時リクエスト数とテストで送信するリクエスト数はある程度大きな数字でないと意味のある結果を得られません。”ab -c 100 -n 10000″と実行したので同時アクセス数が100、リクエスト総数が10000になり、1クライアントあたり100回リクエストを送信した場合と同等となります。
- リクエスト/秒のみでなく、レスポンス時間が重要である
PHPはWeb環境で利用される場合がほとんどです。単位時間あたりの処理回数も重要ですが、レスポンス時間もとても重要です。
これらのポイントを踏まえ、Opcache有り/無しを比較します。
Opcache有り | Opcache無し | |
---|---|---|
Requests per second | 1733.17 | 340.96 |
Time per request(ms) | 57.698 | 293.285 |
longest request(ms) | 90 | 508 |
Time taken for tests(sec) | 5.770 | 29.329 |
Opecache有りの方がかなり速いことは直ぐわかります。
- 毎秒リクエスト数は約5倍Opcache有りが高速
- リクエスト処理時間も約5倍Opecache有りが高速
- 最も処理時間がかかったリクエストも約5倍Opcaeche有りが高速
- 全体の処理時間も約5倍Opcache有りが高速
Opcache(APCでも同じ)有りと無しで性能の差が数割程度しかない、ということは普通のWebアプリではありません。一般的に数倍の差が出ます。
このテストケースの場合、データベースを利用していないのでデータベースサーバーにアクセスする時間が必要ないのでリクエスト数/処理時間に差が出やすい、と言えます。しかし、データベースサーバーを利用している場合でもPHPプログラムが高速に処理できます。これは少ないWebアプリサーバーで多くのユーザーからのリクエストを処理できることを意味します。Opcache無しなら5台のWebサーバーが必要なところが、Opcache有りなら1台のWebサーバーで十分、となるケースは普通にあります。
また、大量のアクセスがないサイトでも「リクエスト開始から完了までの時間が短い=ページ表示が速い」ので意味がない訳ではありません。
まとめ
まれにバイトコードキャッシュが原因でトラブル(動的にスクリプト/データを生成しているのに読み込まれないなど)に巻き込まれることもありますが、バイトコードキャッシュを導入するだけで、数倍PHPスクリプトが速く実行されることを期待できます。
動的にスクリプト/データを生成している場合、リフレッシュ期間(キャッシュの有効期限)を指定したり、キャッシュさせない設定も可能です。
APCでも十分速くなりますが、現在のPHPのバイトコードキャッシュ標準はOpcacheです。もし利用していないなら是非利用してみてください。
PHP 5.6+Opcacheでかなり高速化できることが分かったと思います。PHP7ならどうなるのか?と思うかかも知れません。あるサイトではPHP 5.6 Opecahe有りとPHP7 Opcache無しではほぼ同等の性能でした。PHP7でもOpcacheを入れると数倍高速化されます。大量のアクセスでWebアプリの性能が問題となっている場合、できるだけ早くPHP7に移行することをお勧めします!