青い照明のサーバールームに並ぶネットワーク機器のラック
現場の実践

PHPフレームワークをEC2で自前運用すべきか、判断基準を整理する

目次を見る

Djangoで運用してきたシステムをPHP系フレームワーク(Laravel等)に置き換える、あるいは新規サービスでPHP系を選ぶ場面で、必ず出てくるのがインフラの持ち方です。オンプレのサーバー、あるいはEC2(AWSの仮想サーバーサービス)上に自前でLAMP環境(Linux・Apache・MySQL・PHP)を構築して運用するか、マネージドなPHPホスティングやコンテナ基盤に寄せるかで、運用負荷もコストも大きく変わります。

DjangoからPHP系フレームワークへの移行を検討しているインフラ担当・SREの方に向けて、アプリケーション層の設計差分ではなく、運用・監視・障害対応の観点から何を基準に環境を選ぶべきかを整理します。フレームワーク自体の構造比較はアプリケーション開発者の領域ですが、それを動かす基盤の選定はインフラ側の責任範囲です。

なぜこの判断が必要になるのか

DjangoのWSGI(Webサーバーとアプリケーションをつなぐ標準規格)アプリケーションは、Gunicornのようなアプリケーションサーバーをプロセスとして常駐させ、Nginxがリバースプロキシとして前段に立つ構成が一般的です。

一方でPHP系フレームワークは、リクエストごとにプロセスが立ち上がって処理を終えたら終了する、という実行モデルが伝統的に採用されてきました。public/index.phpがエントリーポイントとなり、Apache のmod_phpやPHP-FPM(FastCGI Process Manager、PHPプロセスを効率的に管理する仕組み)経由でNginxから呼び出されます。

この実行モデルの違いは、監視すべき指標やプロセス管理の考え方に直結します。Djangoのgunicornワーカー数を見ていたエンジニアが、そのままの感覚でPHP-FPMのプールサイズを設計すると、リクエスト集中時にプロセス枯渇を起こすことがあります。移行のタイミングで、インフラをどう組み直すかを一度立ち止まって判断する必要があります。

判断軸1: 実行モデルの違いをどこまで意識するか

PHP-FPMはpm.max_childrenという設定値で同時実行プロセス数の上限を管理します。Djangoのgunicornにおける--workersに近い概念ですが、PHPは1リクエストごとにプロセス(またはスレッド)を使い切って終了するため、長時間実行のバッチ処理や常駐プロセスの設計思想がDjangoとは異なります。

Celeryのような非同期タスクキューをDjangoで使っていた場合、PHP系フレームワークではLaravelのQueueやJobといった仕組みに置き換わります。これらはRedisやSQSをバックエンドにでき、Supervisorやsystemdでワーカープロセスを常駐管理する点はDjango+Celeryの構成とほぼ同じです。運用監視の設計はここを揃えれば大きく崩れません。

判断軸2: マネージドサービスに寄せるか自前構築か

AWSであればElastic Beanstalk、Lightsail、あるいはFargate(サーバーレスコンテナ実行基盤)でPHP環境をマネージドに動かす選択肢があります。オンプレやEC2で自前にLAMP/LEMP環境を組む選択肢と比較すると、パッチ適用やスケーリングの手間が大きく変わります。

自前構築を選ぶ場合、PHPのバージョンアップグレード(例えばPHP 7.4から8.x系への移行)の際に、拡張モジュールの互換性検証やcomposer.jsonの依存関係解決を自分たちで行う必要があります。Djangoのrequirements.txtとPythonバージョンの組み合わせ管理に近い作業ですが、PHPのメジャーバージョン間の非互換は言語仕様レベルで発生することがあるため、検証工数を見積もっておく必要があります。

判断軸3: 障害発生時に何を見て切り分けるか

Djangoではアプリケーションログとgunicornのアクセスログ、WSGIエラーログを追えば大半の障害原因にたどり着けます。PHP系では加えてPHP-FPMのスローログ(slowlog設定で有効化する、処理に時間がかかったリクエストを記録するログ)とApache/Nginxのエラーログ、さらにOPcache(PHPのバイトコードキャッシュ機構)の状態確認が必要になる場面があります。

メモリリークやプロセス肥大化の切り分けも実行モデルの違いが影響します。Djangoのworkerプロセスが常駐する構成ではpstopで長時間実行プロセスのメモリ推移を追いますが、PHP-FPMはリクエストごとにプロセスがリサイクルされるため、pm.max_requests(一定リクエスト数ごとにプロセスを再起動する設定)を適切に設定しておかないと、メモリリークの検知そのものが遅れます。

監視ツール側では、DatadogやNew RelicのAPM(アプリケーションパフォーマンス監視)がPHP-FPMのプールメトリクス(アクティブプロセス数・キュー待ち数)を専用ダッシュボードで提供しています。Djangoのgunicornメトリクスと同じ感覚で見られる項目もあれば、PHP特有の指標も混ざるため、移行時にダッシュボードを作り直す前提で計画したほうが安全です。

判断軸4: 運用コストの内訳がどう変わるか

Djangoの常駐プロセス型構成は、アイドル時でもメモリを一定量占有し続けます。PHP-FPMのオンデマンドプロセス管理(pm = ondemand)を使うと、リクエストがない時間帯はプロセスを落としてメモリを解放できるため、トラフィックの波が大きいサービスではコスト効率が良くなる場合があります。

一方でオンデマンド設定はプロセス起動のレイテンシーを増やすため、レスポンスタイムのSLO(サービスレベル目標)が厳しい場合はpm = dynamicstaticの方が適していることもあります。ここはトラフィックパターンと許容レイテンシーを見て決める部分です。

観点Django(WSGI/gunicorn)構成PHP-FPM構成
プロセスモデル常駐ワーカーリクエスト単位で使い捨て
主な監視対象workerメモリ・キュー滞留FPMプール使用率・スローログ
非同期処理Celery+Redis/RabbitMQLaravel Queue+Redis/SQS等
コスト特性常時一定負荷ondemand設定で波に追従可能
実行モデルの違いを把握しないまま監視ダッシュボードだけ流用すると、障害の予兆を見逃します。

ケース別の推奨

  • トラフィックが安定していて、Djangoで培った監視スタック(Datadog等)をそのまま流用したいなら、まずEC2上にNginx+PHP-FPMを自前構築し、既存のログ集約基盤にログを流し込む構成から始める
  • スパイクの大きいトラフィックでコスト効率を優先するなら、Fargateやマネージドコンテナ基盤に載せ、pm = ondemandを軸にオートスケーリングと組み合わせる
  • 小規模チームで運用工数を最小化したいなら、Laravel Forgeのような専用デプロイ管理サービスやマネージドPHPホスティングを検討する
  • 既存のCeleryワーカー資産をそのまま活かしたい場合は、キュー部分だけRedisを共有インフラとして残し、Laravel Queueに移行する段階的アプローチを取る

あえて見送るべき条件

監視基盤やアラート設計を作り直す余力がないタイミングでの移行は避けたほうが安全です。実行モデルの違いを踏まえずに既存のDjango向けアラート閾値をそのまま流用すると、PHP-FPMのプロセス枯渇を検知できない状態が続きます。

また、PHPのバージョンアップグレード検証工数を確保できない場合、古いPHPバージョンのまま新フレームワークを本番投入するのは避けるべきです。セキュリティパッチの提供期限が切れたバージョンで運用を続けるリスクは、Djangoでも同様に議論されてきた話であり、言語が変わっても優先度は下がりません。

まとめ

DjangoからPHP系フレームワークへの移行は、コードの書き方だけでなく実行モデルそのものが変わる点を押さえておく必要があります。

判断のポイントは次の4つに集約されます。

  • プロセスモデルの違い(常駐 vs 使い捨て)を理解した上でプロセス管理設定を見直す
  • マネージド基盤と自前構築のどちらを選ぶかをチームの運用工数で決める
  • 障害切り分けに使うログ・メトリクスをPHP-FPM向けに作り直す
  • コスト最適化はトラフィックパターンとSLOのバランスでpm設定を選ぶ

まず着手できる一歩として、現在のphp.iniwww.conf(PHP-FPMのプール設定ファイル)を開き、pmの設定値とmax_childrenの上限を確認してみてください。Djangoのworker数と比較しながら、想定トラフィックに対して余裕があるかどうかがひとつの目安になります。

参考

Laravel for Django Developers: A Practical Guide to Laravel Architecture

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。