php-fpm (FastCGI Process Manager) の調査をしていて,学びが多かったので,簡単にまとめておこうと思う.予想していた以上にパフォーマンスが出てないことに驚いたけど,SRE として,インフラ改善 + アプリケーション改善の施策を考えて実行していかないとなー!
重要なパラメータ
php-fpm の設定ファイル /etc/php-fpm.d/www.conf
で,特に重要なパラメータは以下の5個だった.
なお,今回は pm = dynamic
の前提としている.
- pm.max_children
- pm.start_servers
- pm.min_spare_servers
- pm.max_spare_servers
- pm.max_requests
pm.max_children
fork 可能な子プロセスの最大値を意味する.
; The number of child processes to be created when pm is set to 'static' and the ; maximum number of child processes to be created when pm is set to 'dynamic'. ; This value sets the limit on the number of simultaneous requests that will be ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP ; CGI. ; Note: Used when pm is set to either 'static' or 'dynamic' ; Note: This value is mandatory. pm.max_children = 100
インスタンスのメモリサイズと php-fpm の平均メモリ使用量から試算すると良いと思う.平均メモリ使用量は以下のようにして確認できる.1番上のプロセスは親なので無視して,その他のプロセスの平均値を計算する.
以下の例だとプロセスの稼働時間も出力していて,アプリケーションでメモリリークなどが発生している場合,稼働時間の長さとメモリ使用量に相関がある可能性があるため,考慮しておくと良さそう.
$ ps aux | grep php-fpm | grep -v grep | awk '{print $6, $10, $11}' 5896 0:00 php-fpm: 82260 0:19 php-fpm: 80264 0:18 php-fpm: 81216 0:26 php-fpm: 83432 0:18 php-fpm: 80552 0:16 php-fpm: (中略)
もしアクセスがスパイクして,この pm.max_children
に達してしまうと,php-fpm のエラーログに以下のような警告が吐かれる.絶対に見落としちゃダメなログだと思う.
[01- 1月-2016 00:00:00] WARNING: [pool www] server reached pm.max_children setting (100), consider raising it
pm.start_servers
php-fpm を起動した直後に自動的に fork されるプロセス数を意味する.
; The number of child processes created on startup. ; Note: Used only when pm is set to 'dynamic' ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 pm.start_servers = 5
pm.min_spare_servers & pm.max_spare_servers
アイドル状態でプーリングしているプロセス数の最小値と最大値を意味する.
; The desired minimum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' pm.min_spare_servers = 5 ; The desired maximum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' pm.max_spare_servers = 35
pm.max_requests
定期的にプロセスを fork するためのリクエスト数閾値を意味する.以下の例だと1000回リクエストを受けるとプロセスが再起動することになる.
コメントに書いてある通り,メモリリークを起こすライブラリに対するワークアラウンドとして使えるけど,継続的にリクエストを受けるアプリケーションの場合は無効にしておくのが良さそう.また fork し直すコストも考慮が必要そうなので,使うなら臨機応変に.
; The number of requests each child process should execute before respawning. ; This can be useful to work around memory leaks in 3rd party libraries. For ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. ; Default Value: 0 pm.max_requests = 1000
seems busy って出てるけど...
アクセスがスパイクすると pm.max_spare_servers
の値を超えて pm.max_children
に近付いていくログが吐かれるけど,結局 pm.max_children
以上のプロセスは fork できないため,あくまで状況確認としてのログとして認識して良いと思う.ログには pm.start_servers
or pm.min/max_spare_servers
を増やすって書いてあるけど,結局これはアイドル状態のプロセスを増やして新規に fork するコストを下げるだけのメリットしか無さそうで,その必要があるなら増やしても良いかなと思う.
[01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 0 idle, and 42 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 0 idle, and 47 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 52 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 57 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 62 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 67 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 72 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 77 total children [01- 1月-2016 00:00:00] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there are 0 idle, and 82 total children
Zabbix でプロセス数を監視する
キーに proc.num[php-fpm]
と設定してアイテムを用意しておくだけで監視できるようになるので便利!
まとめ
あぁ php-fpm ...!w
相談に乗って頂いた @ariarijp に感謝!🎉