PHP-FPM徹底解説:仕組み・設定・チューニング・運用ベストプラクティス

はじめに — FPMとは何か

FPM(FastCGI Process Manager、一般的には「PHP-FPM」と呼ぶ)は、PHP アプリケーションを FastCGI として実行・管理するためのプロセスマネージャです。主に Nginx と組み合わせて使われ、従来の mod_php に比べてプロセス管理やパフォーマンス面、セキュリティ面で多くの利点があります。本コラムでは PHP-FPM の仕組み、主要設定、チューニング、運用上の注意点、トラブルシューティングまで深掘りします。

基本的なアーキテクチャ

PHP-FPM はマスター(親)プロセスと複数のワーカ(子)プロセスで構成されます。マスタープロセスは設定の読み込み、ワーカプロセスの起動・監視を行い、ワーカは実際に PHP スクリプトを処理します。Web サーバ(例:Nginx)は FastCGI プロトコルで PHP-FPM にリクエストを渡します。通信は UNIX ドメインソケット(例:/run/php/php7.4-fpm.sock)か TCP ソケット(例:127.0.0.1:9000)が使えます。

重要な設定項目(pool.d/*.conf)

主に /etc/php/*/fpm/pool.d/ 以下にプールごとの設定があります。代表的なディレクティブは以下の通りです。

  • listen — 接続先ソケット(UNIX ソケットか IP:PORT)
  • user / group — ワーカの実行ユーザ/グループ
  • pm — プロセスマネージャのタイプ(static / dynamic / ondemand)
  • pm.max_children — 同時起動できる最大ワーカ数(重要)
  • pm.start_servers, pm.min_spare_servers, pm.max_spare_servers — dynamic 用の起動/スパーサーバ数
  • pm.process_idle_timeout — ondemand 用のアイドル終了時間(例えば 10s)
  • pm.max_requests — 子プロセスが再生成されるまでに処理するリクエスト数(メモリリーク回避に有効)
  • request_terminate_timeout — リクエストの最大実行時間(タイムアウトでプロセスを終了)
  • request_slowlog_timeout, slowlog — スローログの検出と保存先
  • access.log, catch_workers_output — ワーカの標準出力/エラーをログに残す設定

pm のモード比較と選び方

pm 設定は運用負荷とリソースに合わせて選びます。

  • static — 常に pm.max_children のプロセスを常駐させる。メモリが十分で、ピークが予測しやすい環境に向く。
  • dynamic — pm.start_servers で起動し、需要に応じて pm.min_spare_servers〜pm.max_spare_servers の範囲で増減。汎用的で多くのケースに適合。
  • ondemand — リクエストが来た時にプロセスを起動し、アイドル時に終了。アイドル期間が長いサーバや少ないメモリで運用する場合に有効だが、初回リクエストで起動遅延が発生する。

チューニングの考え方(実例を含む)

最も重要なのは pm.max_children の決定です。1つの大雑把な算出式:

  • pm.max_children ≒ floor((総利用可能メモリ - OS および他プロセスの必要メモリ) / 1プロセスあたりの平均メモリ)

1プロセスあたりの平均メモリは、実運用で top/ps や smem、またはツールで測定します。OPcache や拡張モジュールは共有メモリを使うため、単純に RSS を足すだけでは過小評価する場合があります。

その他のポイント:

  • pm.max_requests を設定して長時間動作によるメモリリークを緩和する(例:500〜10000)。
  • request_terminate_timeout を設定してハングするリクエストを自動終了させる(例:30s〜300s、アプリに合わせる)。
  • opcache を有効にして PHP の初期化時間とメモリを改善する。ただし opcache のメモリはプロセス間で共有される。
  • listen を UNIX ソケットにするか TCP するか:同一ホストで稼働する場合は UNIX ソケットが高速でファイルパーミッション管理に優れる。複数サーバで PHP-FPM を分散する場合は TCP(IP:PORT)を使う。

Nginx と連携する基本設定例

代表的な Nginx の fastcgi 設定(抜粋):

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

UNIX ソケットを使う場合は socket の所有者・パーミッション(listen.owner, listen.group, listen.mode)を正しく設定し、Nginx の worker ユーザと一致させるかアクセス可能にしておきます。

監視・ステータス取得

PHP-FPM はステータス機能(pm.status_path)や ping 機能を持ち、稼働中のプロセス数、idle/active、リクエスト数などを返すことができます。Nginx 側で専用 location を作り、内部リクエストで取得して監視ツール(Prometheus など)に渡す構成が一般的です。外部に露出させる場合は必ず IP 制限や認証をかけてください。

Prometheus 連携には php-fpm 用の exporter(例:php-fpm_exporter)を使うとメトリクス収集が容易です。

運用でよくある問題と対処法

  • 502 Bad Gateway — 原因は php-fpm が落ちている、ソケットパス不一致、socket パーミッション、または pm.max_children を超えてワーカが割り当てられていること。まず php-fpm の状態、ログ(error_log、pool の slowlog)を確認する。
  • メモリ枯渇/OOM — pm.max_children が多すぎる可能性。上記の算出式で見直す。コンテナ環境では cgroup メモリ制限に注意。
  • ハングや長時間処理 — request_terminate_timeout や slowlog を設定し、原因となるスクリプトを特定する。
  • ログの急増 — catch_workers_output や access.log の設定により大量ログが出るとディスクを圧迫するため、ローテーションやログレベルを見直す。

セキュリティ面の考慮

主要ポイント:

  • プールごとに user/group を分けて権限分離する(例:アプリごとに異なるユーザ)。
  • listen.socket のパーミッション(listen.owner/group/mode)を適切に設定し、Nginx 以外からのアクセスを制限する。
  • 外部にステータスや管理エンドポイントを公開しない。内部ネットワークや IP 制限、認証を必ず設ける。
  • 必要があれば chroot や open_basedir、disable_functions など PHP 側の制限を検討する。

コンテナ化・クラウドでの運用

コンテナ環境では一つのコンテナに PHP-FPM を単体で動かすケースが一般的です。systemd は不要で、フォアグラウンドで起動(--nodaemonize)します。メモリ制限はコンテナの上限に連動するため、pm.max_children はコンテナメモリに合わせて算出してください。また、ロギングは stdout/stderr に出すか外部ログドライバで集約するのが運用上楽です。

ベストプラクティスまとめ

  • まずは本番に近い負荷でワーカあたりの実メモリ消費量を計測し、pm.max_children を算出する。
  • pm.max_requests と request_terminate_timeout を設定し、長時間運用でのメモリ膨張やハングを防ぐ。
  • ステータスや slowlog を有効にして監視・アラートを整備する。
  • UNIX ソケットを使う場合はパーミッション管理に注意。TCP はネットワークの設定を慎重に。
  • 設定変更はまずステージングで検証し、systemctl reload などで停止を伴わず反映する(再起動は簡易だが短時間の接続断が発生するため計画的に)。

設定例(プール)

[www]
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
request_terminate_timeout = 300s
php_admin_value[error_log] = /var/log/php7.4-fpm.log
php_admin_flag[log_errors] = on

おわりに

PHP-FPM は PHP を高負荷下で安定稼働させるための重要なコンポーネントです。設定は単にドキュメントのデフォルトを使うだけでなく、実際のアプリケーション特性(メモリ消費、リクエストの処理時間、トラフィックの波)に合わせて調整する必要があります。監視とログの整備、段階的なチューニングを行えば、可用性とパフォーマンスを両立できます。

参考文献