php-fpm をチューニングしてみました

唐突にチューニングしてみたくなった。
大まかな流れとしては、

  1. 設定ファイル(デフォルトのまま使っているので、/etc/php-fpm.d/www.conf の値を変えてみる
  2. ベンチマーク(Apache Bench)をまわす
  3. vmstat や top をみてボトルネックを探る
  4. 1 に戻る

といったところ。

www.conf の設定項目

  • pm = static or dynamic (一応、他に ondemand というのもある)
    • php-fpm 子プロセス数の制御方法
      • static は固定
      • dynamic はアクセスによって増減させる
    • dynamic はプロセスの増減によるオーバーヘッドが発生するらしいので、static で性能改善することを目論んでいたが、ぶっちゃけさしたる差は感じなかった。
  • pm.max_children
    • php-fpm 子プロセスの最大数
    • 同時に処理可能なリクエストの最大数になる
    • 大きすぎるとメモリが枯渇してスラッシングが発生する
  • pm.start_servers
    • php-fpm 起動時の子プロセス数
    • pm = dynamic の時のみ有効な設定
    • そんなに再起動させることもないだろうけど
  • pm.min_spare_servers, pm.max_spare_servers
    • php-fpm 子プロセスのうち、アイドル状態のプロセスの数を制御する
    • pm = dynamic の時のみ有効な設定
    • アイドル状態の子プロセスについてはキルされるが、この設定に基づいた数が、待ち受けのために残される。
    • なかなか難しいが、こちらのサイト が詳しかった。

Apache Bench

恥ずかしながら知らなかったのだけど、Apache をインストールするとデフォルトでついてくる。
使い方はとても簡単。

ab  -n <総リクエスト数>  -c <同時リクエスト数> <URL>

結果の詳しい見方は省略するが、Request per second (1秒当たりの処理数) がデカければイイ感じ。

どうなったか

このサーバのスペックは、SWAP 領域を追加しました の通り、2core、512MB メモリ & 512 GB Swap である。そして、メモリ消費多すぎて OOM 走ってたくらいなので、 メモリ消費量がボトルネックになりそうだ。

1子プロセスのあたりのメモリ消費量は、概ね 35MB くらいだったが、 pm.max_children を 12 以上に設定するとメモリが足りなくなり、スラッシングが発生した。
こうなると激遅になるので、 pm.max_children は10に設定した。(11でも良かったけど、実測でさしたる差がなかったので、少し余裕をみて)

子プロセス数が 10 に制限されたので、ab の同時リクエスト数を 10 以上に増やしても、CPU 待ちプロセスは常に 10 で張り付いた。この状態でCPU使用率もカツカツだったので、これ以上は php-fpm チューニングではどうしようもない感じ。CPU もメモリも余さず使っている。
その他の項目も、ab のベンチではほぼ意味がない感じ。すぐに子プロセスは最大値までフォークするので、オーバーヘッドは殆ど無視できるということだろう。
pm = static にしても、実測としては殆ど差がなかった。

ちなみにチューニングする前は pm.max_children は 14 だったので、高負荷をかけるとバリバリスラッシングと Failed request が発生していた。

チューニング後、大抵の条件で Request per second が 6 以上、Failed request が発生しなくなったので、なかなか成果があった。

追記

CPU がボトルネックの状況で、プロセス数を増やしても意味ないんじゃ、、、てことで、思い切って pm.max_children を減らしていった。
案の定、パフォーマンスを落とさずに子プロセスを減らすことができた。
最終的にはコア数と同じ 2 まで減らし、そこまで減ったので pm も static に変更した。単純計算で 35MB * (10 – 2) = 280MB 程度メモリ消費を減らせたのではないだろうか。
ついでに Request per second も少し上がって 6.4 程度になった。