PHP はどこにでもあり、おそらくインターネット Web 上で最も広く導入されている言語です。
ただし、特に高度な同時実行システムに関しては、その高性能機能についてはあまり知られていません。そしてそれが、そのような特殊なユースケースでは、Node (はい、言語ではないことはわかっています)、Go、Elixir などの言語が引き継がれている理由です。
そうは言っても、サーバー上の PHP パフォーマンスを向上させるためにできることはたくさんあります。この記事では、
php-fpm
側に焦点を当てます。これは、Nginx を使用している場合にサーバー上で設定する自然な方法です。
php-fpm
が何であるかをご存知の場合は、最適化に関するセクションに進んでください。

PHP-fpmとは何ですか?
DevOps の側面に興味を持っている開発者は多くありません。興味を持っている開発者の中でも、内部で何が起こっているのかを知っている人はほとんどいません。興味深いことに、ブラウザが PHP を実行しているサーバーにリクエストを送信するとき、最初の連絡先となるのは PHP ではありません。代わりに、HTTP サーバーが使用されます。その主なものは Apache と Nginx です。これらの「Web サーバー」は、PHP に接続する方法を決定し、リクエストのタイプ、データ、ヘッダーを PHP に渡す必要があります。

最新の PHP アプリケーションでは、上記の「ファイルの検索」部分は
index.php
であり、サーバーはすべてのリクエストをそこに委任するように構成されています。
さて、Web サーバーが PHP に正確にどのように接続するかは進化しており、核心をすべて説明しようとすると、この記事は爆発的に長くなるでしょう。しかし、大まかに言えば、Apache が Web サーバーの主流として君臨していた時代には、PHP はサーバー内に含まれるモジュールでした。
したがって、リクエストが受信されるたびに、サーバーは新しいプロセスを開始し、PHP が自動的に組み込まれて実行されます。このメソッドは
mod_php
と呼ばれ、「モジュールとしての PHP」の略です。このアプローチには限界がありましたが、Nginx は
php-fpm
で克服しました。
php-fpm
では、PHP を管理する責任があり、プロセスはサーバー内の PHP プログラムにあります。言い換えれば、Web サーバー (この場合は Nginx) は、PHP からデータを送受信する方法を知っている限り、PHP がどこにあるのか、どのようにロードされているのかを気にしません。必要に応じて、この場合の PHP を、それ自体が受信リクエストに対する子 PHP プロセスを管理する別のサーバーとして考えることもできます (つまり、リクエストがサーバーに到達し、サーバーが受信してサーバーに渡されます) — かなりクレイジーです! :-P)。
Nginx のセットアップを行ったことがある場合、または Nginx のセットアップを行ったばかりの場合は、次のようなものに遭遇するでしょう。
location ~ .php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
私たちが興味を持っている行は次のとおりです:
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
これは、
php7.2-fpm.sock
という名前のソケットを通じて PHP プロセスと通信するように Nginx に指示します。したがって、受信リクエストごとに、Nginx はこのファイルを通じてデータを書き込み、出力を受信するとブラウザに送り返します。
繰り返しになりますが、これは何が起こっているのかを最も完全または最も正確に示したものではありませんが、ほとんどの DevOps タスクについては完全に正確であることを強調しなければなりません。
それはさておき、これまでに学んだことを要約しましょう。
- PHP はブラウザから送信されたリクエストを直接受信しません。 Nginx などの Web サーバーが最初にこれらを傍受します。
- Web サーバーは PHP プロセスに接続する方法を知っており、すべてのリクエスト データを PHP に渡します (文字通りすべてを貼り付けます)。
- PHP がその役割を完了すると、応答を Web サーバーに送り返し、Web サーバーはそれをクライアント (またはほとんどの場合ブラウザ) に送り返します。
またはグラフィック的に:

ここまでは素晴らしいのですが、ここで、PHP-FPM とは一体何なのかという、100 万ドル規模の疑問が生じます。
PHP の「FPM」部分は「Fast Process Manager」の略で、サーバー上で実行されている PHP が単一のプロセスではなく、生成、コントローラー、および強制終了されるいくつかの PHP プロセスであることを派手に表現したものです。この FPM プロセス マネージャーによってオフになります。 Web サーバーがリクエストを渡すのはこのプロセス マネージャーです。
PHP-FPM はそれ自体がまったくのウサギの穴なので、必要に応じて自由に探索してください。ただし、ここでは説明はこれくらいで十分です。 🙂
PHP-fpm を最適化する理由
では、すべてが順調に進んでいるときに、なぜこのようなダンスについて心配する必要があるのでしょうか?そのままにしておいてはいかがでしょうか。
皮肉なことに、これはまさに私がほとんどのユースケースに対して提供するアドバイスです。セットアップが正常に動作し、特別な使用例がない場合は、デフォルトを使用してください。ただし、1 台のマシンを超えて拡張することを検討している場合は、1 台のマシンから最大値を絞り出すことが不可欠です。これにより、サーバーの料金を半分 (またはそれ以上) に削減できるからです。
もう 1 つ認識すべきことは、Nginx は巨大なワークロードを処理するために構築されていることです。同時に数千の接続を処理できますが、PHP セットアップに同じことが当てはまらない場合、Nginx は PHP が現在のプロセスを終了して、次に、Nginx が提供するために構築された利点は決定的に否定的です。
さて、それはさておき、
php-fpm
を最適化するときに正確に何を変更するかを見てみましょう。
PHP-FPMを最適化するにはどうすればよいですか?
php-fpm
の構成ファイルの場所はサーバー上で異なる場合があるため、それを見つけるために調査を行う必要があります。 UNIX の場合は find コマンドを使用できます。私の Ubuntu では、パスは
/etc/php/7.2/fpm/php-fpm.conf
です。もちろん、7.2 は私が実行している PHP のバージョンです。
このファイルの最初の数行は次のようになります。
;;;;;;;;;;;;;;;;;;;;;
; FPM Configuration ;
;;;;;;;;;;;;;;;;;;;;;
; All relative paths in this configuration file are relative to PHP's install
; prefix (/usr). This prefix can be dynamically changed by using the
; '-p' argument from the command line.
;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;
[global]
; Pid file
; Note: the default prefix is /var
; Default Value: none
pid = /run/php/php7.2-fpm.pid
; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /var
; Default Value: log/php-fpm.log
error_log = /var/log/php7.2-fpm.log
すぐにわかることがいくつかあります。行
pid = /run/php/php7.2-fpm.pid
は、どのファイルに
php-fpm
プロセスのプロセス ID が含まれているかを示します。
/var/log/php7.2-fpm.log
が
php-fpm
のログの保存場所であることもわかります。
このファイル内に、次のようにさらに 3 つの変数を追加します。
emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s
最初の 2 つの設定は警告であり、1 分以内に 10 個の子プロセスが失敗した場合、メインの
php-fpm
php-fpm
が自動的に再起動されるように php-fpm プロセスに指示しています。
これは堅牢ではないように聞こえるかもしれませんが、PHP は有効期間が短く、メモリ リークを引き起こすプロセスであるため、障害が多発した場合にメイン プロセスを再起動すると、多くの問題を解決できます。
3 番目のオプション
process_control_timeout
、親プロセスから受信したシグナルを実行する前に、子プロセスにこの時間待機するように指示します。これは、たとえば、親プロセスが KILL シグナルを送信するときに、子プロセスが何かの途中である場合に便利です。 10 秒あれば、タスクを完了して正常に終了できる可能性が高くなります。
驚くべきことに、これは
php-fpm
構成の核心で
はありません
。これは、Web リクエストを処理するために、
php-fpm
別の構成を持つ新しいプロセスのプールを作成するためです。私の場合、プール名は
www
で、編集したいファイルは
/etc/php/7.2/fpm/pool.d/www.conf
でした。
このファイルがどのように始まるかを見てみましょう:
; Start a new pool named 'www'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('www' here)
[www]
; Per pool prefix
; It only applies on the following directives:
; - 'access.log'
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = www-data
group = www-data
上記のスニペットの最後をざっと見ると、サーバー プロセスが
www-data
として実行される理由の謎が解決されます。 Web サイトの設定時にファイル権限の問題が発生した場合は、ディレクトリの所有者またはグループを
www-data
に変更している可能性が高く、これにより PHP プロセスがログ ファイルに書き込んだり、ドキュメントをアップロードしたりできるようになります。 。
最後に、問題の原因であるプロセス マネージャー (pm) の設定にたどり着きます。通常、デフォルトは次のようになります。
pm = dynamic
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 200
では、ここでの「 動的 」とは何を意味するのでしょうか?これについては、公式ドキュメントが最もよく説明していると思います (つまり、これは編集中のファイルの一部になっているはずですが、そうでない場合に備えてここに再掲しました)。
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static - a fixed number (pm.max_children) of child processes;
; dynamic - the number of child processes are set dynamically based on the
; following directives. With this process management, there will be
; always at least 1 children.
; pm.max_children - the maximum number of children that can
; be alive at the same time.
; pm.start_servers - the number of children created on startup.
; pm.min_spare_servers - the minimum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is less than this
; number then some children will be created.
; pm.max_spare_servers - the maximum number of children in 'idle'
; state (waiting to process). If the number
; of 'idle' processes is greater than this
; number then some children will be killed.
; ondemand - no children are created at startup. Children will be forked when
; new requests will connect. The following parameter are used:
; pm.max_children - the maximum number of children that
; can be alive at the same time.
; pm.process_idle_timeout - The number of seconds after which
; an idle process will be killed.
; Note: This value is mandatory.
したがって、可能な値が 3 つあることがわかります。
- 静的 : 何があっても一定数の PHP プロセスが維持されます。
-
動的
:
php-fpm
任意の時点で存続させるプロセスの最小数と最大数を指定できます。 - ondemand : プロセスはオンデマンドで作成および破棄されます。
では、これらの設定はどのように重要なのでしょうか?
簡単に言えば、トラフィックが少ない Web サイトの場合、「動的」設定はほとんどの場合リソースの無駄になります。
pm.min_spare_servers
を 3 に設定していると仮定すると、Web サイトにトラフィックがない場合でも、3 つの PHP プロセスが作成され、維持されます。このような場合、新しいプロセスを開始するタイミングをシステムに決定させる「オンデマンド」の方が良いオプションです。
一方、大量のトラフィックを処理する Web サイトや、迅速に応答する必要がある Web サイトは、この設定で罰せられます。新しい PHP プロセスを作成し、それをプールの一部にし、監視することは、避けるべき余分なオーバーヘッドです。
pm = static
を使用すると、子プロセスの数が固定され、PHP の管理ではなくリクエストの処理に最大のシステム リソースが使用されるようになります。この方法を使用する場合は、ガイドラインと落とし穴があることに注意してください。これに関するかなり内容の濃い、しかし非常に役立つ記事が
ここに
あります。
最後の言葉
ウェブのパフォーマンスに関する記事は戦争を引き起こしたり、人々を混乱させたりする可能性があるため、この記事を閉じる前にいくつかの言葉が必要だと思います。パフォーマンスのチューニングには、システムの知識と同じくらい当て推量と闇の術が重要です。
php-fpm
設定をすべて暗記したとしても、成功が保証されるわけではありません。
php-fpm
の存在について全く知らなかった場合でも、心配して時間を無駄にする必要はありません。すでにやっていることを続けて続けてください。
同時に、パフォーマンス中毒になってしまうことも避けてください。はい、PHP を最初から再コンパイルし、使用しないモジュールをすべて削除することで、さらにパフォーマンスを向上させることができますが、このアプローチは運用環境では十分に賢明ではありません。何かを最適化するという全体的な考え方は、ニーズがデフォルトと異なるかどうかを確認し (そうすることはめったにありません!)、必要に応じて小さな変更を加えることです。
PHPサーバーの最適化に時間を費やす準備ができていない場合は、パフォーマンスの最適化とセキュリティを担当するKinstaのような信頼性の高いプラットフォームの活用を検討してください。