カメノドットコム
Debian大好きでメインで節操ない感じ。
GMOもわりと好き。
RSS feedly

PHP7のphp-fpmをチューニング

PHP7 がめっちゃ速かったので php-fpm もチューニングしてみることにします。
何事もレッツトライです。

---- [PR] ----
現在契約中 : GMOクラウドのVPS : お名前.com
今後契約するかも : お名前.com VPS
--------------

チューニングの準備と手順

php-fpm は「pm = dynamic」で運用します。パフォーマンスは少し落ちるようですが、メモリが潤沢でない場合はこちらのほうがよさげです。
手順としては「/opt/php7/etc/php-fpm.d/www.conf」を編集して php-fpm と Apache を再起動して Apache Bench でテスト。
php-fpm のエラーログを確認しながら各数値を調整していきます。
Apache2.4のevent_mpmをチューニング設定 でも使用した ab コマンドと、今回新たに tailhtop というコマンドも使用します。
htop でモニタリングしながら行いますので、SSH で最低 2本 接続して作業します。
Debian はデフォルトで htop が入っていないようですので、パッケージからインストールします。

# apt-get install htop

これでチューニングの用意が出来ました。
早速 htop と叩いてモニタリングを開始しましょう。

php-fpmをチューニングする

/opt/php7/etc/php-fpm.d/www.conf」を編集していきます。
いじる項目は主に「pm.max_children」「pm.start_servers」「pm.min_spare_server」「pm.max_spare_server」の4つです。
これらにも関係性がありますので先にご紹介。

「pm.start_servers」の値は「pm.max_children」と「pm.max_spare_server」の値を超えないようにする。
「pm.min_spare_server」の値は「pm.max_children」「pm.start_servers」「pm.max_spare_server」の値を超えないようにする。
「pm.max_spare_server」の値は「pm.max_children」の値を超えないようにする。

こういうぱっと見ではややこしげな決まり事がありまして。
PHP: Configuration - Manual (pm) に説明がありますが、英語です。頑張れー。頑張ろー。

んと。数式っぽく書きなおさないと自分でもよくわからない(苦笑)

pm.max_children > pm.max_spare_server > pm.start_servers, pm.min_spare_server

ということになりますので「pm.start_servers」から決めていけばいいかなーと思います。多分 コア数 になると思いますが(笑)
まずはデフォルト設定の確認です。

# vi /opt/php7/etc/php-fpm.d/www.conf
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

それっぽい数字が並んでます。いじらなくていいんじゃないかと思うくらいです。
この設定でどんな感じの負荷がかかるのかをチェックします。
使用する PHPスクリプト は テスト用ファイル群ターボール にある「test.php」を使用します。ご覧いただければわかりますが、大した処理はしてません。表示結果が「test.html」と同じになるようにしてあるだけです。
負荷をかける Aapche Bench は、ちょっと かなり見栄を張って「1,000 のクライアントが、同時に 10 の接続」とします。同時接続総数 1万 です。
例によって VPS でのローカルテストにします。本当はリモートからのほうがいいんですけどね。回線が安定してる方はリモートからどうぞ。

# cd /opt/php7/var/log
# ab -c 1000 -n 10000 http://localhost/test/test.php
# ls
php-fpm.log

ハイ。Apache で「Length」エラーが出ましたが php-fpm はエラーがありません。
ということは PHP が足を引っ張っているということが考えられますね。HTMLファイル の時にはエラーがなかった負荷レベルなので。
「pm.start_servers」と「pm.max_children」を少し増やしてみます。

# vi /opt/php7/etc/php-fpm.d/www.conf
pm.max_children = 6
pm.start_servers = 3
# rm /usr/local/httpd_01/logs/access_log; rm /usr/local/httpd_01/logs/error_log
# svc -d /etc/service/php7-fpm; svc -d /etc/service/httpd-01
# svc -u /etc/service/php7-fpm; svc -u /etc/service/httpd-01
# sleep 10
# ab -c 1000 -n 10000 http://localhost/test/test.php

この程度の変更ではほとんど変化がありませんでした。
あ、ログファイルの削除は同じ状態でテストできるようにってことです。daemontools の後に sleep 10 とあるのは、サーバ再起動後にちょっと時間をあげると安定する傾向があるからです。
「pm.start_servers」は コア数 で固定して「pm.max_children」を コア数 と同じ数だけ増やしてみます。ウチは 3vCPU なので +3 していきます。
php-fpm に余裕があって Apache がエラー吐いたり吐かなかったりするビミョーなラインは下記設定でした。

# vi /opt/php7/etc/php-fpm.d/www.conf
pm.max_children = 18
pm.start_servers = 3
pm.min_spare_servers = 1
pm.max_spare_servers = 3

GMOクラウドのVPS のマイクロプラン(2GBプラン)は 3vCPU なので「pm.min_spare_server」と「pm.max_spare_server」はデフォルトのままです。
コア数によってはこちらも変更していいと思います。多分「pm.max_spare_server」は コア数 で「pm.min_spare_server」は コア数×0.5 あたりが目安かなーと。
調整した結果、ウチの環境では下記の値を中心に微調整するのが良さげです。

; Error 0
pm.max_children = 24

; Length Error
pm.max_children = 27

; Length Error, apr_socket_recv: Connection reset by peer (104)
pm.max_children = 30

「pm.max_children = 27」で「pm.min_spare_server」を変更してみると面白そうなのでやってみました。

; すべて Length Error
pm.min_spare_servers = 1
pm.min_spare_servers = 2
pm.min_spare_servers = 3

ふむ。やはりアクセスを捌くには「pm.start_servers」と「pm.max_children」が肝のようです。
しかし実験してみて新たな発見をしました。
「pm.min_spare_server」を増やすと CPU の負荷が増減するようです。
下記3パターンの設定での htop を比較してみました。

pm.max_children = 24
pm.start_servers = 3
pm.min_spare_servers = 1
pm.max_spare_servers = 3

「pm.min_spare_servers = 1」での htop の様子です。

pm.max_children = 24
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 3

「pm.min_spare_servers = 2」での htop の様子です。

pm.max_children = 24
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 3

「pm.min_spare_servers = 3」での htop の様子です。

ビミョーな違いしかないような……気がする。
……と見せかけて。
「pm.min_spare_servers = 2」にすると、何故か「apr_socket_recv: Connection reset by peer (104)」が多発しました。
よって「pm.min_spare_servers = 1」か「pm.min_spare_servers = 3」がいいんだろうということで ab を連続 10回 ずつやってみました。
再起動やログファイルの削除は行っていません。文字通りぶっ続けです。

pm.min_spare_servers = 1pm.min_spare_servers = 3
1回目0Length: 177
2回目Length: 257Length: 133
3回目00
4回目Length: 1990
5回目0Length: 34
6回目Length: 116Length: 219
7回目Length: 2650
8回目Length: 480
9回目apr_socket_recv: Connection reset by peer (104)Length: 254
10回目Length: 76Length: 192

あららー。「apr_socket_recv: Connection reset by peer (104)」出ちゃいました。
「pm.min_spare_servers = 1」では CPU が 99.9% のフル稼働になるケースがありました。
「pm.min_spare_servers = 3」の場合は 98% あたりが最大で、時によっては 80% 程度でクリアすることもありました。
高めの負荷をかけたのでギリギリな感じですが、ウチの環境では設定値が大決定したので発表します。

pm.max_children = 24
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 3

php-fpm には余裕がありますが Apache がカッツカツです。
でも大丈夫。同時アクセス 1万 とか絶対ないから、ウチは。
「1万 とか普通だぜ?」という素敵なサイトを運営している方は GMOクラウドのVPS では最低でも 4G のプランを契約してください。アフィで稼いでるでしょ?(笑)

Sponsored Link