Contents
要点サマリ(結論と推奨アクション)
本番環境での負荷試験や破壊的操作は行わないでください。ステージング専用環境を用い、運用チームへ事前告知した上で実行します。ここでは Laravel 10 と PHP 8.3 の差分を再現可能に評価する方針と短期の推奨アクションを示します。
推奨アクション(短期)
まずはステージングで「現行 PHP(例: 8.2)→ PHP 8.3」の差分ベンチを実施します。結果に応じてカナリアや詳細解析へ進めてください。
- ステージングで現行版のベースラインを取得する。
- 同一構成で PHP 8.3 に切替えて同じ試験を再実行する。
- 5〜10 回の本試行で統計的評価を行い、差分が明確な場合にのみ次工程へ進める。
判断フロー(簡易)
以下の流れで判断します。各段階でデータを残し、設定やバイナリの差を明確にします。
- 現行 PHP でベースライン計測(設定・composer.lock を保存)
- PHP 8.3 を導入して同一試験を実行
- 差分を統計的に評価(必要に応じてブートストラップ)
- 問題なければカナリア運用、閾値超過時は最適化/ロールバック
比較指標とテストケース設計
比較指標を統一しておくことで、結果解釈のブレを減らせます。ここでは必須指標と業務で再現しやすい代表シナリオを列挙します。
比較指標の定義
以下の指標を必ず収集し、計測方法と保存形式(JSON/CSV)を統一してください。
- RPS(requests per second):成功リクエスト数 ÷ 試行時間。NTP で時刻同期する。
- p50 / p95 / p99:クライアント側の分布を保存して算出する。テールの差異を重視。
- 平均応答時間(ms):分布と併せて解釈する。
- スループット(帯域):レスポンスサイズ × RPS。ネットワークI/Oを評価する。
- メモリ使用量(プロセス単位/ピーク):php-fpm ワーカーの RSS/VSZ(/proc/
/status 等)。 - CPU 使用率:mpstat, pidstat 等でコアごとの負荷を保存する。
- エラー率:クライアント側の 5xx とタイムアウト、サーバログの突合。
- 同時接続数/キープアライブ影響:長時間コネクションを扱う場合は必須。
計測ログは JSON か CSV で保存し、フィールド例を統一してください(timestamp, scenario, php_version, run_id, rps, p50_ms, p95_ms, p99_ms, avg_mem_mb, cpu_pct, errors など)。
軽量 API(DB 非依存)
フレームワークオーバーヘッドやランタイム最適化の影響を測ります。設定例や期待ボトルネックを明示してください。
- 目的:小さな JSON を返す API のレイテンシ。
- 設定例:payload 0.5–2 KB、concurrency 50–200、duration 60s、ウォームアップ 30s。
- 期待ボトルネック:PHP 実行、OPcache、コンテキストスイッチ。
DB 集約クエリ(複雑な JOIN / 大量データ読み出し)
DB ボトルネックで PHP バージョン差が埋もれるケースの確認をします。
- 目的:多数行を読み取る複雑な SELECT。
- 設定例:データセット数百万件規模、concurrency 10–50、ページネーション別試験。
- 期待ボトルネック:DB CPU・I/O、ネットワーク、ORM 発行クエリ数。
テンプレート描画(Blade 重いレンダリング)
多層のテンプレート描画で PHP の実行コストを評価します。
- 目的:部分テンプレートやコレクションループでの CPU/メモリ負荷測定。
- 設定例:HTML 50–200 KB、concurrency 20–100。
- 期待ボトルネック:テンプレートキャッシュ、メモリ使用量。
バッチ処理/CLI(長時間ジョブ)
CLI ジョブでのガベージコレクションやメモリリーク影響を評価します。
- 目的:artisan コマンドやジョブワーカーのスループット。
- 設定例:1 ジョブ処理時間測定、処理件数/分。
- 期待ボトルネック:GC、メモリ解放、I/O。
高同時接続負荷(長時間保持)
キープアライブが支配的なシナリオを評価します。
- 目的:多数の同時コネクションを長時間保持。
- 設定例:concurrency 500+、接続維持時間を長めに。
- 期待ボトルネック:FPM プロセス枯渇、接続キュー、ファイルディスクリプタ。
外部 API 依存ケース(外部をスタブ化)
外部依存を固定して内部差分を測ります。
- 目的:外部呼び出しをモックし、外部遅延が差分に与える影響を分離する。
- 設定例:外部遅延 50–300 ms を想定したモック。
- 期待ボトルネック:外部待ち時間とタイムアウト設定の影響。
それぞれのシナリオは、コールド測定とウォーム測定の方針を別に定義して実行してください(後述)。
再現可能なベンチマーク環境の前提
環境差が結果に直結します。ここでは再現性を高めるために固定すべきハード/ソフトと、試行ごとに保存すべきスナップショットを示します。
ハードウェアとネットワーク(例)
測定は可能な限り専有リソースで行ってください。共有ノイズは結果を毀損します。
- OS:Ubuntu 22.04 等。カーネルは配布版推奨。
- CPU:8 vCPU(専有コア推奨)。
- メモリ:例 32 GB(環境に応じて調整)。
- ディスク:DB 用は NVMe、アプリは SSD。
- ネットワーク:1 Gbps 専有回線。仮想化の有無を明記。
ソフトウェア固定事項
バージョンと設定を試行間で固定してください。差分は必ず記録します。
- PHP:比較対象(例:8.2.x → 8.3.x)。SAPI(php-fpm/cli)を明記。
- Laravel:composer.lock とコミットハッシュを固定。
- Web サーバ:nginx バージョンを記録。
- DB:バージョンと主要設定(innodb_buffer_pool_size など)を固定。
- Redis:使用する場合は同一バージョン、できれば専用インスタンスを用意。
PHP / OPcache / FPM の前提例
基本設定は試行ごとに保存して再現できるようにします。
- opcache.enable=1(有効化)
- opcache.memory_consumption(例: 256M)
- opcache.max_accelerated_files(composer のファイル数に合わせる)
- opcache.validate_timestamps=0(本番相当)※デプロイ時 FPM 再起動を前提にする場合のみ
- FPM pool: pm=dynamic(例)、pm.max_children は後述の算出式で決定する。
- memory_limit をワーカー想定に合わせる(例: 512M)
Laravel 側の前提とキャッシュ
アプリのキャッシュ状態は試行間で統一します。
- composer install --no-dev --optimize-autoloader を使用。
- php artisan config:cache / route:cache の適用有無を試験設計で固定。
- opcache.preload の有無も試験因子にする場合は詳細を記録。
メトリクス収集と環境スナップショット
計測データと設定の紐付けが重要です。
- サーバ:vmstat, mpstat, iostat などを稼働させる。
- PHP:php-fpm status、opcache_get_status の出力を保存(デバッグ用)。
- DB:slow query log、EXPLAIN の保存。
- スナップショット保存:/etc/php/*/fpm/php.ini、www.conf、nginx.conf、composer.lock、.env を試行ごとに保存する。
ベンチマーク手順とサンプルコマンド/スクリプト
手順は「準備→ベースライン取得→PHP 8.3 適用→同条件で再実施→比較」です。コールド測定とウォーム測定はプロトコルを分けて行います。
推奨ツール
ベンチ用クライアントとプロファイラ、システムメトリクスの組合せを揃えます。ツールごとの特徴に注意して選んでください。
- 負荷ツール例:wrk、k6、hey、ab(簡易比較用)。
- システムメトリクス:vmstat、mpstat、iostat、pidstat。
- プロファイラ/トレースは下記で比較する。
Blackfire
Blackfire は SaaS 型のプロファイリングサービスで、簡単に比較プロファイルが取れる点が強みです。エージェントが必要で企業向け機能が充実しますが、OSS 無料枠や有料プランの制約を確認してください。
Tideways
Tideways はサーバサイドの APM / プロファイリングに強く、XHProf 互換の API も提供します。商用プランが主ですが、オンプレ向けの導入も可能です。PHP 8.3 対応状況を確認してください。
Xdebug
Xdebug はローカル開発向けのトレーサーでオーバーヘッドが大きめです。本番相当の負荷試験では有効化しないのが一般的で、詳細なトレースは開発環境や低負荷検証で使用します。
XHProf とその現状
元々の XHProf はメンテナンスが停滞している実装が多く、PHP の最新バージョンで互換性に問題が出ることがあります。Tideways のフォークや互換レイヤーを検討するか、Blackfire/Tideways を優先検討してください。
代表的なベンチコマンド例
各コマンド例は環境に応じてパラメータ調整してください。サービス名やバイナリパスはディストリやコンテナで異なります(後述の注意参照)。
-
wrk(レイテンシ表示)
wrk -t12 -c400 -d60s --latency http://localhost/api/endpoint > wrk_result.txt -
k6(スクリプト化・JSON 出力)
k6 run --vus 200 --duration 60s --out json=k6_result.json script.js -
hey(軽量ツール)
hey -n 100000 -c 200 http://localhost/endpoint > hey_result.txt -
ab(古典的)
ab -n 100000 -c 200 -g ab_gnuplot.tsv http://localhost/endpoint/
各種メトリクス同時収集(別ターミナルで):
- vmstat 1 > vmstat.log &
- iostat -x 1 > iostat.log &
- mpstat 1 > mpstat.log &
OPcache/FPM の初期化と「コールド/ウォーム」方針
コールド測定とウォーム測定は目的が異なります。手順を分けて実行してください。
コールド測定プロトコル(例)
コールド測定は「初回リクエストでの起動/コンパイル等の影響」を測る目的です。
- PHP-FPM を再起動してプロセスを完全に入れ替える(またはコンテナを再作成)。
- opcache を空の状態にする(php -r 'opcache_reset();' を併用しても良い)。
- Laravel のキャッシュ(view, config)もリセットしておく(必要に応じて)。
- 指定のスクリプトで単発の負荷(例: 1 回の短時間 run)を実行し、初回挙動を収集。
- 再現性のため、同環境を再構築して同一条件で複数回実施する。
注意:php -r 'opcache_reset();' の効果や FPM のサービス名は環境依存です。systemctl restart php8.3-fpm はディストリでサービス名が異なる場合があります(例: php-fpm, php8.3-fpm, php7.4-fpm)。service コマンドや docker restart を用いる場合は環境に合わせてください。
ウォーム測定プロトコル(例)
ウォーム測定はキャッシュが温まった状態でのスループットやレイテンシを測ります。
- PHP-FPM を一度起動(または再起動)して安定化させる。
- ウォームアップ用の負荷(例: 30〜60 秒または数千リクエスト)を流し、OPcache や view キャッシュを十分に埋める。
- ウォームアップ後に本試行を N 回(例: 5〜10 回)実行する。各本試行の間は基本的に opcache_reset や FPM 再起動を行わない。
- 必要に応じて、ウォームアップ→複数本試行→FPM 再起動→再ウォームアップというグループ単位で比較する。
重要:ウォーム測定で毎回 opcache_reset や FPM 再起動を行うと「ウォーム状態」の測定になりません。測定方針(cold/warm)を試験設計に明記してください。
データベース/キャッシュのリセット(DB エンジン別・ステージング限定)
データベースや Redis のキャッシュクリアはエンジンごとに異なり、危険操作が含まれます。共有環境での破壊的操作は厳禁です。
共通注意
- 本番共有リソースでの破壊的操作は禁止です。必ずステージングまたは専用インスタンスで実行してください。
- スナップショットやバックアップから短時間で復帰できる仕組みを用意してください。
MySQL / MariaDB
- MySQL 8.0 以降は query cache が廃止されています。RESET QUERY CACHE は使えません。
- InnoDB のバッファプールを「確実に空にする」にはサーバ再起動が確実ですが、安全性を重視するなら専用ステージング DB を使うか、テスト用スキーマを作ってデータを差し替える方法を推奨します。
- MariaDB の古いバージョンに query cache がある場合は公式ドキュメントを確認し、ステージング専用でのみ FLUSH QUERY CACHE 等を実行してください。
PostgreSQL
- セッションレベルのキャッシュは DISCARD ALL 等でクリアできますが、共有バッファ(shared buffers)や OS のファイルキャッシュはセッションコマンドではクリアできません。
- サーバ再起動または専用インスタンス/スナップショットを用いるのが安全です。ファイルキャッシュを drop する手段(/proc/sys/vm/drop_caches)はシステム全体に影響するため、本番での実行は避けてください。
Redis
- redis-cli FLUSHALL は全データを消去するため共有環境では危険です。代替として次を検討してください。
- 専用の Redis インスタンスまたは別データベース番号を使う。
- FLUSHDB(特定 DB 番号)を使う。
- キープレフィックス(bench:*)を付け、SCAN と DEL を使って対象キーのみ削除する(大量キーでは注意)。
- ステージング限定でのみ完全消去を行う旨を強く明記する。
例(ステージング専用、DB 1 を空にする):
- redis-cli -n 1 FLUSHDB
キーを特定プレフィックスで削除する簡易例(注意して実行):
- redis-cli --scan --pattern 'bench:*' | xargs -r -n 100 redis-cli del
(上記は大規模データで遅延やブロッキングが発生するため、本番では使用不可)
OS ファイルキャッシュ
- ファイルシステムのキャッシュをクリアする /proc/sys/vm/drop_caches はシステム全体に影響するため、本番での利用は禁止です。代わりに専用環境で再起動するか、スナップショットから復元する方法を採用してください。
実行フロー(推奨)
- 事前スナップショット取得(設定ファイル、composer.lock、DB スキーマ)
- ベースライン(現行 PHP)で cold/warm 両方を取得(各 N 回)
- PHP 8.3 に切替、同一手順で計測
- 出力を正規化して比較(CSV/JSON)
- 統計評価(t 検定/ブートストラップ)で有意差を確認する
環境依存性への注意
- systemctl のサービス名や php.ini のパスは配布やパッケージ名で異なります。サービス名は systemctl list-units | grep php などで確認してください。
- コンテナ化環境では docker restart
、Kubernetes では pod 再作成で再現します。 - php.ini の実際の読み込み先は php --ini や php-fpm -i | grep 'Loaded Configuration File' で確認してください。
実測例の提示と差分分析(レイヤー別)
ここでは提示方法と差分分析のチェックポイント、統計的評価の実行例を示します。以下の表は合成サンプルで出典はありません。実運用の判断には自社の再現テスト結果を用いてください。
合成サンプル(例示・出典なし)
以下は合成データの例示です。実値ではありませんので、結果の解釈や意思決定に用いないでください。
| シナリオ | PHP 8.2 RPS | PHP 8.3 RPS | Δ(%) | p95 8.2 (ms) | p95 8.3 (ms) | 平均メモリ差 (MB) |
|---|---|---|---|---|---|---|
| 軽量 API | 1,200 | 1,260 | +5% | 40 | 38 | +5 |
| DB 集約 | 240 | 250 | +4% | 200 | 190 | +8 |
| テンプレート描画 | 80 | 88 | +10% | 420 | 380 | +12 |
(上表は合成の例示です。外部ベンチを引用する場合は必ず出典を明記してください)
差分分析のチェックポイント
差分が出た場合、レイヤー別に原因を切り分けます。
- ランタイム層(PHP エンジン)に起因する改善は CPU バウンドケースで顕著になる。
- OPcache のヒット率不足はスローダウンの要因になるため opcache_get_status を確認する。
- ORM 層の N+1 は DB 側の遅延でバージョン差を隠すため、クエリ数と個別クエリ時間を必ず測る。
- 外部 API の待ち時間はモック化して比較する。
プロファイリング手順(簡易)
- Blackfire / Tideways などでホットスポットを取得する。
- Flamegraph を生成してコールスタックの偏りを確認する。
- 必要に応じて strace / perf でシステムコール側の待ちを調査する。
- DB の slow query log と EXPLAIN を突合する。
統計的評価の実行例(Python)
有意差検定の簡単な実行例を示します。前提として、各バージョンで同一シナリオを複数回(理想は 10 回以上)実行して結果 CSV を用意してください。
- t 検定(独立サンプル)の例(scipy が必要):
|
1 2 3 4 5 6 7 8 9 10 11 |
import numpy as np from scipy import stats # 例:RPS の配列 rps_old = np.array([1200, 1198, 1210, 1205, 1190]) rps_new = np.array([1260, 1255, 1270, 1268, 1250]) t, p = stats.ttest_ind(rps_new, rps_old, equal_var=False) print("t=", t, "p=", p) # p < 0.05 なら有意差(ただし前提条件の確認が必要) |
- ブートストラップによる差の信頼区間(差の平均):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import numpy as np def bootstrap_diff(a, b, n=10000): diffs = [] for _ in range(n): da = np.random.choice(a, size=len(a), replace=True) db = np.random.choice(b, size=len(b), replace=True) diffs.append(db.mean() - da.mean()) diffs = np.array(diffs) return np.percentile(diffs, [2.5, 50, 97.5]) ci = bootstrap_diff(rps_old, rps_new) print("95% CI for mean difference:", ci) |
判断基準例:p < 0.05 かつ相対差 > 5% を「実務上の意味あり」とする、など業務で閾値を決めてください。t 検定は正規性や等分散の仮定があるため、分布特性に応じてブートストラップを使うと堅牢です。
最適化ポイント、互換性、運用コスト、移行ロードマップ、チェックリスト、FAQ
移行に伴う実務的な留意点と即効性のある設定をまとめます。特に互換性確認と監視設計を優先してください。
推奨設定と即適用チェックリスト
まずは影響の小さい項目から適用し、効果を定量的に確認します。
- APP_DEBUG を false にする。
- composer dump-autoload --optimize を実行する。
- composer install --no-dev --optimize-autoloader(本番用)を使用する。
- php artisan config:cache / route:cache を適用する。
- OPcache を有効化し、opcache.memory_consumption を適正化する(例: >=128M)。
- opcache.max_accelerated_files を composer のファイル数に合わせて増やす(例: 150k–300k)。
- opcache.validate_timestamps=0 を検討する(デプロイ手順で FPM 再起動を行う場合)。
- opcache.preload は有効化効果とメモリ増加をステージングで確認する。
- Xdebug は本番で無効にする。
- 監視に p95/p99、エラー率、FPM ワーカー利用率、OPcache 使用量を追加する。
pm.max_children の算出(安全マージン含む)
ワーカー数の算出では OS と他プロセスの余裕を確保してください。平均RSSだけに依存するのは危険です。
- 推奨式(概念):
- 利用可能メモリ(MB) = 総メモリ(MB) × (1 - システム予約比) - 他プロセス使用量(MB)
-
pm.max_children = floor(利用可能メモリ / ワーカー当たり推定RSS)
-
安全マージン:システム用に総メモリの 10–20% を確保することを推奨。
- ワーカーRSSの算出:ピーク値や 95 パーセンタイルを使うと安全側に寄せられます。
例(簡易):
- 総メモリ 32GB = 32768 MB、システム予約 15% → 32768 × 0.15 ≈ 4915 MB
- 他プロセス合計 4GB = 4096 MB
- 利用可能 ≈ 32768 - 4915 - 4096 = 23757 MB
- ワーカーRSS 想定 200 MB → pm.max_children = floor(23757 / 200) = 118
調整ポイント:pm.max_requests、pm.start_servers、pm.min_spare/max_spare もワークロードに合わせてチューニングしてください。
移行ロードマップ(段階的)
- 依存性確認(拡張や Composer パッケージの PHP 8.3 対応)
- ステージング導入と自動テストの全通
- ベンチ取得(上記プロトコル)と差分評価
- 必要な最適化(OPcache、FPM 設定、クエリ最適化)
- カナリア運用(段階的トラフィック切替)
- ロールアウト(監視強化、アラート閾値の確認)
監視アラート例(運用で設定する閾値例)
- p95 レイテンシがベースライン比 +20% 超でアラート。
- エラー率(5xx)がベースライン比 +0.5% 以上でアラート。
- CPU 使用率が 90% 継続でアラート。
- FPM idle ワーカーが枯渇したらアラート。
互換性確認の優先事項
- 使用中の PHP 拡張(PECL 含む)が PHP 8.3 に対応するか確認する。
- composer check-platform-reqs, composer outdated で依存関係を点検する。
- Laravel 10 のアップグレードガイドにある breaking changes を確認する。
- CI で統合テストを走らせ、差分を自動検知する。
よくある質問(FAQ)
Q: PHP 8.3 に上げれば必ず高速化しますか?
A: ワークロード依存です。CPU バウンド処理では恩恵が出やすい一方、DB 主導処理では差が限定的です。必ず自社ベンチで確認してください。
Q: JIT を有効化すべきですか?
A: 計算集約型処理では効果が出る可能性がありますが、典型的な Web リクエストでは限定的です。ステージングで比較してください。
Q: opcache.preload は推奨ですか?
A: アプリ初期化のオーバーヘッド低減に有効ですが、メモリ増加とデプロイ運用(再起動)が必要です。ステージングで検証してください。
Q: 何回の試行が必要ですか?
A: 傾向把握は 5 回、統計的判断には 10 回以上を推奨します。t 検定やブートストラップで有意差を確認してください。
まとめ
Laravel 10 を PHP 8.3 へ移行する場合、性能影響はワークロードによって大きく異なります。ステージング環境でコールド/ウォーム両方のプロトコルを明確に分け、十分な反復試行と統計的評価を行った上で、段階的なカナリア導入を行ってください。DB キャッシュの扱いや Redis の破壊的操作などはエンジン依存かつリスクが高いため、専用環境でのみ実行することを厳守してください。