PHP 8.2.13 + php-fpm を Amazon Linux 2023、nginx の裏で動かしている環境の話です。ピーク時に 5 分間で約 1,200 req/s、1 リクエストあたりの PHP 実行時間は p95 で 180ms 程度。前任者が設定した pm.max_children = 200 のまま運用していて、昼のバーストで 502 が散発し、dmesg には oom-kill のログが残っていました。メモリは 8GB、FPM 以外に nginx と Redis クライアントが同居しています。
まず実測します。FPM の status ページを有効にして、ピーク時のプロセスあたりの RSS を取ります。
; /etc/php-fpm.d/www.conf
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 500
pm.status_path = /fpm-status
# ピーク時に10秒おきで3回、平均RSSを確認
ps -o rss= -C php-fpm | awk '{s+=$1; n++} END {printf "%.1f MB avg / %d procs\n", s/n/1024, n}'
# status の抜粋
curl -s unix:/run/php-fpm/www.sock:/fpm-status?full | head -20
実測は平均 62MB、上位プロセスで 85MB でした。8GB から nginx と OS で 1.2GB を引くと、FPM に渡せるのは 6.8GB 程度。85MB × 40 = 3.4GB で余裕を見て 40 に設定。pm.max_requests = 500 は、長時間動くワーカーで断片化した RSS がじわじわ増えるのを観測したためで、これはメモリリークの隠蔽ではなく、増加を 500 リクエスト単位でリセットして上限を読みやすくするためのものです。
なぜ dynamic かというと、夜間は 3 req/s 程度まで落ちるため static で 40 を常駐させるのは無駄で、start_servers を 8 にしておけば立ち上がり時の fork スパイクも避けられます。ただし dynamic は負荷上昇時に子プロセス生成が追いつかず、短時間だけ 502 が出ることがあります。それを許容できないなら static にして、RSS 実測値から逆算して子プロセス数を絞るべきです。
効かない条件も書いておきます。OPcache の opcache.memory_consumption を 256MB など大きく取っている場合、共有メモリは RSS に重複計上されないため、ps の RSS 合計は実際のメモリ消費より小さく出ます。また pm.max_children を上げても、MySQL の max_connections や nginx の worker_connections が先に詰まれば 502 は減りません。私が踏んだのは、RSS を測った直後にデプロイで OPcache をリセットし、その直後のピークで各ワーカーの RSS が一時的に膨らんで OOM になったケースです。デプロイ直後は pm.max_children を一時的に下げるか、ローリングで再起動する運用に変えました。
みなさんの環境では、pm.max_children を決めるときに RSS のどの値を基準にしていますか。平均、p95、それとも最大値でしょうか。


0 条评论
还没有评论,写下第一条。