監視システムから、PHPを使っているページの応答異常を知らせるアラートが届きました。サーバーを確認すると、php-fpm.service が停止しています。サービスを再起動すれば一時的に復旧する可能性はありますが、この時点では停止した原因が分かっていません。また、再起動すると停止時のプロセス状態など、調査に必要な情報が失われることがあります。そのため、まずログとサーバーの状態を確認してから復旧作業を進めました。
調査の結果、php-fpm が消費していたメモリに、定期実行された dnf-makecache のメモリ使用が重なり、OOM(Out of Memory)が発生していたことが分かりました。この記事では、残されたログから原因をたどった手順と、再発防止の考え方を紹介します。
※掲載しているログは、内容に影響しない範囲で一部加工しています。
先に結論
今回確認できた状況は次のとおりです。
- uid=1048 の php-fpm プロセスが50個あり、RSSの合計は約2.6GB
- OOM発生時に動いていた
dnfは、約600MBの匿名メモリを使用 - メモリに余裕がない状態で両者が重なり、OOM Killerが作動
- 最終的にphp-fpmのプロセスが終了し、Webサイトが応答できなくなった
原因は「dnf-makecacheだけ」ではありません。php-fpmのメモリ使用量が大きく、サーバー全体に十分な余裕がなかったところへ、dnf-makecacheの処理が重なったことが障害の引き金になりました。
状況の把握
管理しているサーバー(以下 web01)で、PHPを使うページが軒並みエラーになりました。systemdのステータスを確認すると、次のように表示されていました。
$ systemctl status php-fpm
× php-fpm.service - The PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled)
Active: failed (Result: oom-kill) since ...
Result: oom-kill は、サービス内のプロセスがOOM Killerによって終了させられたことを示します。OOM Killerは、Linuxカーネルが必要なメモリを確保できなくなったとき、プロセスを終了させてシステム全体の停止を避ける仕組みです。
調査では、現在のメモリとスワップの状態も確認します。
free -h
swapon --show
ただし、障害後の空きメモリだけを見ても、発生時の状況は分かりません。原因を特定するには、OOM発生時のカーネルログが必要です。
journalctlでカーネルログを確認する
OOMはカーネルレベルのイベントなので、まず journalctl -k でカーネルログを確認しました。
$ sudo journalctl -k
-- No entries --
何も表示されません。OSが再起動した可能性を考えましたが、uptime では129日間稼働していました。続けて、journalに残っているブート情報を確認します。
$ sudo journalctl --list-boots
IDX BOOT ID FIRST ENTRY LAST ENTRY
0 7f3a8b2c1d4e5f6a... Thu 2026-05-14 03:55:01 JST Fri 2026-05-15 ...
journalに残る最初のエントリは 2026-05-14 03:55:01 でした。一方、php-fpmが停止したのは03:42です。障害発生時のjournalは残っていませんでした。
この情報だけでは、03:55以前のjournalが失われた理由までは断定できません。journaldの停止、ログのローテーション、ファイルの破損、保存容量の制限などが考えられます。/run/log/journal/ に保存される揮発journalはOS再起動時に失われますが、journaldプロセスの再起動だけで必ず消えるわけではありません。
また、journalctl の表示権限が原因でログを読めない場合もあります。一般ユーザーで何も表示されないときは、sudo を付けて再確認します。
/var/log/messagesから調査を続ける
この環境では、同じ時間帯のログが /var/log/messages に残っていました。
sudo grep -i 'oom\|killed process\|out of memory' /var/log/messages
CentOS / RHEL系では、rsyslogがjournaldやsyslogソケットから受け取ったメッセージを /var/log/messages に保存する構成が一般的です。ただし、journaldとrsyslogの連携方法は設定によって異なります。必ず残るとは限らないため、実際の /etc/rsyslog.conf と読み込みモジュールも確認が必要です。
今後の調査に備えてjournalを永続化する場合は、保存先を用意します。
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
永続化した後は、OS再起動後でも journalctl -k -b -1 で前回ブートのカーネルログを参照できます。保存容量の上限も合わせて設計しておくと安心です。
OOM Killerのログを読む
/var/log/messages には、2026年5月11日から断続的にOOMが発生した記録が残っていました。OOM発生時には、カーネルが次のような情報を出力します。
May 11 02:14:27 web01 kernel: dnf invoked oom-killer: gfp_mask=0x..., order=0, oom_score_adj=0
May 11 02:14:27 web01 kernel: Mem-Info:
May 11 02:14:27 web01 kernel: ...(メモリ情報)
May 11 02:14:27 web01 kernel: Tasks state (memory values in pages):
May 11 02:14:27 web01 kernel: [ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name
May 11 02:14:27 web01 kernel: [ 654321] 1048 ... 75000 14500 ... 3200 0 php-fpm
May 11 02:14:27 web01 kernel: ...
May 11 02:14:27 web01 kernel: oom-kill:constraint=CONSTRAINT_NONE,...task=dnf,pid=...,uid=0
May 11 02:14:27 web01 kernel: Killed process ... (dnf) total-vm:848484kB, anon-rss:623236kB, ...
主な項目の意味は次のとおりです。
| 項目 | 内容 |
|---|---|
total_vm | 仮想メモリの割り当て量。タスク一覧ではページ単位 |
rss | RAM上にあるメモリ量。タスク一覧ではページ単位 |
swapents | スワップへ退避しているページ数 |
oom_score_adj | OOM Killerの対象になりやすさを調整する値。-1000で保護、0が標準 |
Killed process | OOM Killerが実際に終了させたプロセス |
anon-rss | 対象プロセスが使用していた匿名メモリの常駐量 |
OOM Killerは、メモリ使用量などから計算したbadness scoreに oom_score_adj を加味して、終了させるプロセスを選びます。oom_score_adj だけで対象が決まるわけではありません。
タスク一覧にある rss をMBへ換算するときは、ページサイズを確認します。
getconf PAGESIZE
x86_64 Linuxでは通常4KiBですが、環境によって異なります。ページサイズが4096バイトなら、rss × 4096 ÷ 1024 ÷ 1024 で概算できます。
障害のタイムライン
ログを時系列に並べると、次の流れになっていました。
| 日時 | 出来事 |
|---|---|
| 5月11日 02:14 | 最初のOOM。dnf のメモリ確保中にOOM Killerが作動し、dnf が終了 |
| 5月13日 04時台 | OOMが再発し、再び dnf が終了 |
| 5月14日 0時台 | OOMが再発 |
| 5月14日 03:42 | OOM Killerがphp-fpmのプロセスを終了 |
| 5月14日 03:42 | systemdが php-fpm.service: Failed with result 'oom-kill'. を記録 |
最初の数回はdnfが終了していましたが、その時点ですでにサーバーは深刻なメモリ不足に陥っていました。5月14日03:42のOOMではphp-fpmが対象となり、Webサイトの停止として表面化しました。
dnf-makecacheとの関連を確認する
最初のログにある dnf invoked oom-killer は、dnfのメモリ確保処理中にOOM評価が始まったことを示します。dnfが根本原因だと断定するメッセージではありません。
一方、同じイベントの Killed process には次の記録がありました。
May 11 02:14:27 web01 kernel: Killed process ... (dnf) total-vm:848484kB, anon-rss:623236kB
このdnfプロセスは、終了時点で約600MBの匿名メモリを使用していました。anon-rss は追加で要求した量ではなく、その時点でRAM上に常駐していた匿名メモリの量です。
今回の環境では、OOM発生時刻と dnf-makecache.service の実行時刻が一致していました。次のコマンドでタイマーと実行履歴を確認できます。
systemctl status dnf-makecache.timer
sudo journalctl -u dnf-makecache.service \
--since "2026-05-11" --until "2026-05-15"
OOMログに task_memcg=/system.slice/dnf-makecache.service とあれば、終了対象となったタスクがdnf-makecacheサービスのcgroupに属していたことも確認できます。ただし、global_oom と記録されている場合は、dnf-makecacheのcgroupだけがメモリ上限に達したのではなく、システム全体でメモリ不足が起きています。
この環境では、php-fpmが常時多くのメモリを使用しているところへ、dnf-makecacheの処理が重なったことがOOMの引き金になったと判断しました。dnf-makecacheが常に数百MBを使用するという意味ではなく、リポジトリ数やメタデータ量、DNFのバージョンによって使用量は変わります。
なぜphp-fpmが終了させられたのか
OOMレポートでは、uid=1048 の php-fpm プロセスが50個あり、1プロセスあたりのRSSは約23〜68MB(平均約52MB)でした。
50プロセス × 約52MB ≒ 約2,600MB
php-fpmだけで約2.6GBを使用していたところへ、dnf-makecacheのメモリ使用が重なりました。サーバー全体で新たなメモリを確保できなくなり、OOM Killerが作動したと考えられます。
どのプロセスが終了対象になるかは、メモリ使用量、oom_score_adj、利用可能なメモリの制約などから決まります。今回の最終イベントではphp-fpmのプロセスが選ばれ、systemdにはサービスの結果として oom-kill が記録されました。
再発を防ぐための対策
php-fpmのプロセス数を見直す
まず、php-fpmがサーバーのメモリ量に対して過剰なプロセス数になっていないか確認します。
grep 'pm\.' /etc/php-fpm.d/*.conf
ps -C php-fpm -o rss= | awk '{ total += $1; count++ } END { printf "processes=%d rss=%.1fMB\n", count, total/1024 }'
pm.max_children は「大きいほどよい」設定ではありません。1プロセスあたりの実測RSSと、PHPに割り当てられるメモリ量から上限を決めます。
pm = dynamic の場合は、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers も確認します。アクセスが少ない環境では pm = ondemand が適する場合もありますが、応答時間とのトレードオフがあるため、負荷を見ながら判断します。
RAMとスワップの容量を確認する
スワップは一時的なメモリ不足を吸収する安全弁になります。
free -h
swapon --show
ただし、スワップはRAMの代わりではありません。スワップへの退避が頻発すると、応答速度が大きく低下します。php-fpmの設定を見直しても必要なメモリを確保できない場合は、RAMの増設やサービスの分離を検討します。
dnf-makecache.timerの停止は一時的な回避策とする
メモリに余裕がなく、対策が終わるまで同じOOMを避けたい場合は、dnf-makecacheのタイマーを一時的に停止できます。
sudo systemctl disable --now dnf-makecache.timer
これにより、パッケージメタデータの定期更新が止まります。恒久的に停止するかどうかは、サーバーの更新運用を確認してから判断してください。手動メンテナンス時には、最新のメタデータを取得したうえで更新を実施します。
OOMの兆候を監視する
OOMが起きてから対処するのではなく、次の項目を監視します。
- メモリとスワップの使用率
- php-fpmのプロセス数とRSS合計
dnf-makecache.serviceの失敗- カーネルログの
oom-kill、Killed process
過去のOOMが見つかった時点で、Webサイトが停止していなくてもメモリ設計を見直す必要があります。
まとめ
今回の障害では、php-fpmが約2.6GBのメモリを使用している状態でdnf-makecacheが実行され、システム全体のメモリ不足が表面化しました。最初はdnfが終了対象になっていましたが、OOMが繰り返された末にphp-fpmが終了し、Webサイトが応答しなくなりました。
調査で重要だった点は次の4つです。
journalctl -kが空でも、権限や保存設定を確認し、/var/log/messagesなど他のログも調べるinvoked oom-killerとKilled processを区別して読む- 個々のプロセスだけでなく、php-fpm全体のRSS合計を計算する
- 引き金となった処理だけを止めず、サーバー全体のメモリ設計を見直す
インフラの監視設定やphp-fpmの設定見直しについてはインフラ管理・監視支援、原因不明の障害調査については障害調査・原因分析からご相談ください。