PHP 8 パフォーマンスチューニング: OpCacheとJITを解説
PHP 8アプリケーションが負荷時に遅く感じることはありませんか?クエリを最適化し、キャッシュを追加しても、応答時間がまだ遅いままです。原因はPHP自体の実行オーバーヘッドかもしれません。2つの強力な機能—OpCacheとJIT—は、正しく設定すればコードを劇的に高速化できます。このガイドでは、それらの仕組みと実際のワークロードに合わせたチューニング方法を説明します。
OpCacheとは何か、なぜ重要なのか
PHPはインタプリタ言語です。各リクエストは通常、ソースファイルを解析してバイトコードにコンパイルしてから実行します。OpCacheはそのコンパイル済みバイトコードを共有メモリに保存するため、後続のリクエストは解析とコンパイルをスキップします。その結果、CPU使用率が下がり、応答時間が速くなります。
OpCacheは多くの本番環境でデフォルトで有効になっていますが、デフォルト設定は控えめです。チューニングすることで、CPUバウンドのアプリケーションではスループットが2〜3倍向上する可能性があります。
主要なOpCache設定ディレクティブ
- opcache.enable: 1に設定して有効化します。(デフォルト: 本番環境では1、CLIでは上書きしない限り0。)
- opcache.memory_consumption: 共有メモリサイズ(MB)。128 MBから始め、
opcache.memory_usageが高い場合は増やします。 - opcache.max_accelerated_files: キャッシュされるファイルの最大数。PHPファイルの総数より大きい素数(例: 10007)に設定します。
- opcache.validate_timestamps: 1の場合、PHPはファイルのタイムスタンプをチェックして変更を検出します。本番環境では0に設定してstat呼び出しを避けます。デプロイ後は手動でキャッシュをクリアする必要があります。
- opcache.revalidate_freq: validate_timestamps=1の場合、タイムスタンプをチェックする頻度(秒)。開発では0、本番では60以上に設定します。
- opcache.interned_strings_buffer: インターン化された文字列用のメモリ(MB)。大規模アプリでは16または32に増やします。
- opcache.fast_shutdown: PHP 7.2+で非推奨、PHP 8.0で削除されました。無視してください。
- opcache.preload: プリロードスクリプトへのパス(PHP 7.4+)。プリロードは起動時にファイルをコンパイルしてキャッシュし、重要なクラスのリクエストごとのオーバーヘッドを排除します。
本番環境向け推奨OpCache設定
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.interned_strings_buffer=32
opcache.preload=/path/to/preload.php
opcache.preload_user=www-data
設定を変更した後は、PHP-FPMを再起動してください。opcache_get_status()でヒット率とメモリ使用量を監視します。
PHP 8のJITを理解する
JIT(Just-In-Time)コンパイルはOpCacheをさらに一歩進めます。実行時にバイトコードをネイティブマシンコードにコンパイルします。これにより、数学的計算などのCPU集約的なタスクが大幅に高速化される可能性がありますが、I/O(データベース、ファイルシステム、ネットワーク)が支配的な典型的なWebリクエストにはほとんど効果がありません。
JITはOpCacheの一部であるため、まずOpCacheを有効にする必要があります。PHP 8では、JITはopcache.jitとopcache.jit_buffer_sizeで設定します。
JIT設定ディレクティブ
- opcache.jit: JITモードを制御します。
tracing(デフォルト)またはfunctionを使用します。値は4桁のCRTOコードです:CRTO。ここで、C=CPU固有の最適化、R=レジスタ割り当て、T=トリガー、O=最適化レベルです。ほとんどのアプリではopcache.jit=tracingで問題ありません。 - opcache.jit_buffer_size: JITコード用のメモリ(バイト単位)。64Mまたは128Mから始めます。0に設定するとJITは無効になります。
- opcache.jit_hot_loop、opcache.jit_hot_func、opcache.jit_hot_return、opcache.jit_hot_side_exit: ホットコード検出のしきい値。通常、デフォルトで問題ありません。
推奨JIT設定
opcache.jit=tracing
opcache.jit_buffer_size=128M
注意: JITはOpCacheが有効な場合にのみ機能します。CLIでは、JITをテストするためにopcache.enable_cli=1を設定する必要があるかもしれません。
OpCache vs JIT: どちらをいつ使うか
| 機能 | OpCache | JIT |
|---|---|---|
| 主な利点 | コンパイル済みバイトコードをキャッシュ | バイトコードをネイティブコードにコンパイル |
| 最適な用途 | すべてのPHPアプリケーション | CPU集約的で長時間実行されるスクリプト |
| I/Oバウンドアプリへの影響 | 高い(解析/コンパイルを削減) | 低い〜なし |
| メモリオーバーヘッド | 中程度 | 追加バッファ |
| 複雑さ | 低い | 中程度 |
ステップバイステップのチューニングガイド
- OpCacheを有効化し、上記の推奨設定を適用します。
- OpCacheを監視するには、
opcache_get_status()またはOpCache GUIなどのツールを使用します。ヒット率99%以上を目指します。 opcache.memory_usageが限界に近い場合はメモリを調整します。- 大規模フレームワーク(Laravel、Symfony)ではプリロードを検討します。頻繁に使用されるクラスをrequireするプリロードスクリプトを作成します。
- アプリがCPUバウンドの場合にのみJITを有効化します。JITありとなしでテストして影響を測定します。
ab、wrk、siegeなどのツールを使用してベンチマークを実行します。1秒あたりのリクエスト数とレイテンシを比較します。- 変更を段階的にデプロイし、問題がないかエラーログを監視します。
よくある落とし穴とベストプラクティス
- 開発環境でvalidate_timestampsを無効にしないでください: コード変更が反映されない理由を考えて時間を無駄にします。
- デプロイ時にOpCacheをクリア: validate_timestamps=0の場合、OpCacheをリセットする必要があります(例: PHP-FPMを再起動するか、
opcache_reset()を呼び出す)。 - JITは万能薬ではありません: 典型的なCRUDアプリでは、OpCacheだけでほとんどの効果が得られます。
- メモリに注意: JITバッファとOpCacheメモリはPHPのフットプリントに追加されます。サーバーに十分なRAMがあることを確認してください。
- プリロードは慎重に使用: プリロードされたファイルは常にメモリに存在します。すべてをプリロードしないでください。
FAQ
JITはすべてのPHPアプリケーションのパフォーマンスを向上させますか?
いいえ。JITは複雑な計算やデータ処理などのCPU集約的なタスクに効果があります。I/OバウンドのWebアプリ(データベースクエリ、API呼び出し)では、効果は最小限です。多くの場合、OpCacheだけで最大の高速化が得られます。
OpCacheが動作しているかどうかを確認するには?
phpinfo()でOpCacheのステータスを確認するか、スクリプトでopcache_get_status()を呼び出します。opcache_enabled => trueと、missesに対して高いhitsカウントを探します。
PHP 7でJITを使用できますか?
いいえ。JITはPHP 8.0で導入されました。PHP 7はOpCacheのみをサポートしています。PHP 7を使用している場合は、OpCacheのチューニングに注力し、JITやその他のパフォーマンス改善のためにPHP 8へのアップグレードを検討してください。
サーバーのパフォーマンスを分析する準備はできましたか?Nginx Log Analyzerをチェックして、アクセスログから洞察を得てボトルネックを特定しましょう。