広告 Linux

サイト表示が遅い問題の調査と修正(php-fpm/MariaDBのメモリ過剰割り当て)

KUSANAGI(nginx + Apache + PHP-FPM + MariaDB)で運用している本サイト(bacchi.me)を含む複数サイトの表示が遅くなる事象が発生したため、調査から対処までの内容を記録しておきます。

症状

bacchi.me など同一 VPS 上でホストしているサイトすべてで表示が遅くなっていました。

調査方法

まずは負荷状況を確認するため、基本的なコマンドで全体像を確認しました。

uptime
free -h
df -h
nproc

結果、以下が判明しました。

  • load average が 12.83(CPUは3コアのみ)と、コア数に対して大幅に過大
  • 物理メモリ2GBに対し、swapを2.5GB/4GB使用

次にプロセス単位で状況を確認しました。

ps aux --sort=-%cpu | head -20
ps aux --sort=-%mem | head -20

単一プロセスがCPUを占有しているわけではなく、php-fpmのworkerプロセスが多数、D状態(ディスクI/O待ち)やR状態で滞留していましたた。

そこで vmstat でメモリのswap in/out とI/O待ち(iowait)の推移を見たところ、決定的な兆候がでていました。

vmstat 1 5
 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 5  0 2521544 204572   8816 385652  107  101   170   108    2    1  5  1 92  2  0
 6  1 2524260  73128   8816 385532  148 2748   148  2750 2878 1562 45  6 48  0  0
 0  5 2532540  74396   8816 384876  272 8516   272  8516 2833 1487 41  3 21 35  0
 0  5 2544272  67460   8816 388776 1020 12472  5116 12472 1964 1575  8  3 12 77  0
 0  5 2554508  69408   8816 388724  612 10968   612 11028 1572 1354  1  2  4 93  0

swap の読み書き(si/so)が継続的に発生し、iowait が瞬間的に77〜93%まで跳ね上がっていました。空きメモリ(free)も数十 MB 程度しか残っておらず、典型的なスワップ・スラッシング状態でした。

原因を掘り下げるため、MariaDBとPHP-FPMのメモリ関連設定を確認しました。

mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
mysql -e "SHOW VARIABLES LIKE 'max_connections';"
grep -E "^pm|^pm\." /etc/opt/kusanagi/php-fpm.d/www.conf

結果は以下の通り。

  • MariaDB innodb_buffer_pool_size = 768M(物理メモリ2GBの約40%)
  • MariaDB max_connections = 900(2GBのVPSには過大)
  • PHP-FPM pm.max_children = 50

実際の php-fpm ワーカー1プロセスあたりの RSS (実使用メモリ)を計測すると、平均 65MB 前後だった。

ps aux | grep 'php-fpm: pool' | awk '{sum+=$6; count++} END {print sum/count, count}'

pm.max_children = 50 × 65MB ≒ 3.3GB となり、MariaDB のバッファプール 768MB と合わせると、瞬間的な必要メモリが物理 RAM (2GB)を大きく超える設計になっていたことが分かりました。アクセスが重なり php-fpm の worker が増えるたびに、Linux カーネルが強制的にページを swap へ追い出し、その結果 I/O 待ちが発生してリクエスト全体が詰まる、という悪循環が起きていました。

修正方法

物理メモリ 2GB に収まる範囲まで、PHP-FPM と MariaDB のメモリ関連設定を縮小ました。

PHP-FPM(/etc/opt/kusanagi/php-fpm.d/www.conf)

項目変更前変更後
pm.max_children5012
pm.start_servers103
pm.min_spare_servers52
pm.max_spare_servers155

MariaDB(/etc/my.cnf.d/server.cnf)

項目変更前変更後
innodb_buffer_pool_size768M256M
max_connections900100

設定ファイルは変更前にバックアップを取得したうえで編集し、以下の順でサービスを再起動して反映しました。

systemctl restart mariadb
systemctl restart php-fpm

修正後の動作

再起動直後はまだ残っていた swap の影響で応答が2秒台でしたが、数秒後には安定し、明確な改善が確認できました。

指標修正前修正後
load average12.832.61
iowait77〜93%0〜2%
bacchi.me 応答時間遅延0.30秒

php-fpm の worker 数も実測7プロセス(上限12)に収まり、swap の新規発生もほぼ止まったようです。

まとめ

複数の WordPress サイトを 2GB という小さめのメモリの VPS に同居させる場合、MariaDB や PHP-FPM のデフォルト・過去の設定値が実メモリに対して過大になっていないか定期的に見直す必要がある。特に php-fpm のpm.max_childrenは「実測RSS × max_children」が物理メモリを超えないよう設計するのが重要だと再確認しました。トラフィックが今後増える場合は、設定チューニングだけでなく VPS 自体のプラン変更も検討したいです。

Sponsor Link

-Linux
-,