Skip to content
Published on

Linux障害対応コマンド完全ガイド: 最初の60秒から根本原因まで

シェア
Authors

はじめに

障害対応で最も無駄になる時間は、コマンドを知らないことから生まれるのではありません。どのコマンドを どの順番で 打つべきかを知らないから生まれます。top を立ち上げて30秒眺め、df を打ち、また top に戻る。そうしているうちに5分が過ぎていきます。

この記事は、「サーバーが遅い」「応答がない」「デプロイ後に様子がおかしい」という連絡を受けた瞬間から実行するコマンドを順番に整理します。このブログにはすでに Linuxパフォーマンスエンジニアリングガイド がありますが、あの記事はプロファイリングとチューニングの方法論を扱っています。この記事は違います。まだ何が問題なのか分からない状態で、候補を一つずつ除外していく順番 がテーマです。

前提は一つです。診断は犯人を探す作業ではなく、容疑者を除外していく作業 です。CPUでなければCPUを消し、メモリでなければメモリを消します。残ったものが答えです。

ディストリビューションの表記は次のとおりです。RHEL系はRHEL/Rocky/AlmaLinux 8以上、Debian系はDebian 12およびUbuntu 22.04以上を基準とします。


1. 最初の60秒 — 標準点検シーケンス

Netflixのパフォーマンスエンジニアリングチームが公開した「最初の60秒」チェックリストは、事実上の業界標準になりました。核心は 一度に10個を投げておいて全体像を先に見てから 深く掘ることです。

uptime
dmesg --level=err,warn --ctime | tail -20
vmstat 1 5
mpstat -P ALL 1 3
pidstat 1 3
iostat -xz 1 3
free -m
sar -n DEV 1 3
ss -s

各コマンドが除外する容疑者は次のとおりです。

コマンド答える問いこれで除外できるもの
uptime負荷は今上がっているのか、下がっているのかすでに終わった障害
dmesgカーネルが何かを殺したり切ったりしたかOOM Kill、ディスクエラー、リンクダウン
vmstat 1CPU待ちかI/O待ちかスワップか三つのうち二つ
mpstat -P ALL全体が忙しいのかコア一つだけが忙しいのかシングルスレッドのボトルネック
pidstat 1どのプロセスが使っているのか無実のプロセスすべて
iostat -xz 1ディスクが詰まっているかストレージ
free -mメモリが実際に足りないのかメモリ
sar -n DEV帯域が飽和しているかネットワークスループット
ss -sソケットが漏れているかコネクションリーク

mpstatpidstatiostatsar はすべて sysstatパッケージ に入っています。デフォルトインストールでない場合が多いので、サーバーを作るときにあらかじめ入れておいてください。

# RHEL系
sudo dnf install -y sysstat
# Debian系
sudo apt install -y sysstat

sar で過去のデータを見るには収集デーモンが動いている必要があります。Debian系は /etc/default/sysstat で有効化の値をオンにして初めて収集が始まります。

sudo systemctl enable --now sysstat

2. ロードアベレージが実際に語ってくれること

uptime の三つの数字は1分、5分、15分のロードアベレージです。ここで二つのことを誤解しがちです。

一つめ、LinuxのロードアベレージはCPU待ちだけを数えるのではありません。実行可能(R)状態だけでなく、中断不可待ち(D状態)のプロセス も含みます。D状態はほとんどがディスクI/OまたはNFS応答待ちです。そのためCPUが遊んでいるのに負荷が40になる状況が起こります。この場合の犯人はCPUではなくストレージです。

二つめ、絶対値より傾きが重要です。1分の値が15分の値より大きければ今悪化している最中で、小さければすでに回復中です。後者なら急いで再起動する理由はありません。

uptime
 14:22:31 up 41 days,  3:11,  2 users,  load average: 12.44, 6.80, 3.15

この出力は「過去15分の間に負荷が4倍に跳ね上がり、今も上がり続けている」という意味です。コア数と比べて初めて意味が出るので、まずコア数を確認してください。

nproc
lscpu | grep -E '^CPU\(s\)|Thread|Core|Socket|Model name'

3. CPUを誰が使っているのか

vmstat 1 の最初の行は 起動以降の平均 なので無視して、2行目から読みます。これはmanページに明記された動作です。

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
 8  1      0 210488  91232 3120440    0    0    12    34  980 2210 71 14  9  6  0

読む順番はこうです。

  • r: 実行待ちのプロセス数。コア数より継続的に大きければCPU飽和です
  • b: I/O完了を待ってブロックされたプロセス数。ここが大きければストレージを疑います。
  • si/so: スワップイン/アウト。0でなければメモリ不足がすでに性能に影響しています。
  • wa: I/O待ち時間の比率。高ければディスク、低いのに遅いならディスクではありません。
  • st: ハイパーバイザーに奪われた時間。クラウドVMでこの値が5を超え続けるならホストが過密であり、自分のサーバーの中では解決できません

全体が忙しいのかコア一つだけが忙しいのかは mpstat で分けます。

mpstat -P ALL 1 3

コア一つだけが100パーセントならシングルスレッドのボトルネックです。スケールアップでは解決せず、コードか設定を見る必要があります。

犯人のプロセスは pidstat で探します。top と違い、累積ではなく区間ごとの値を出し続けてくれる ので、ログに残すのに向いています。

pidstat -u 1 5
pidstat -t -p 1234 1 5

-t オプションはスレッド単位に分解します。JavaやGoのプロセスのようにスレッドが多い場合、どのスレッドが回っているのかを見ることができます。%wait は実行の準備ができているのにCPUをもらえず待った比率なので、ここが高ければ プロセスが遅いのではなくCPUの競合が激しい ということです。

伝統的な ps の組み合わせも依然として有用です。

ps -eo pid,ppid,stat,pcpu,pmem,etime,rss,args --sort=-pcpu | head -15

stat 列に D が見えれば中断不可待ち、Z はゾンビ、T は停止状態です。


4. メモリ — freeのどの数字を信じるか

free -m で初心者が最も頻繁に読み違えるのが free 列です。Linuxは余っているメモリをページキャッシュとして使います。free が小さいのは正常であり、見るべき場所は available 列です。

free -m
               total        used        free      shared  buff/cache   available
Mem:           15884       10233         412         188        5238        5102
Swap:           4095         120        3975

available は「今、新しいプロセスが要求したら回収して渡せる量」というカーネルの推定値です。この値が総量に対して十分に残っていればメモリ不足ではありません。

メモリ不足が疑われるなら、まずカーネルが何を殺したのかを確認します。

dmesg --ctime | grep -i -E 'out of memory|oom-kill|killed process'
journalctl -k --since '2 hours ago' | grep -i oom

dmesg --ctime(-T)は人が読む時刻に変換してくれますが、manページは システムのサスペンド/レジューム後はタイムスタンプが不正確になることがある と警告しています。正確な時刻が必要なら journalctl -k を使ってください。

細かい内訳は /proc/meminfo を見ます。

grep -E 'MemAvailable|Dirty|Writeback|Slab|SReclaimable|Committed_AS' /proc/meminfo

Dirty が大きく、しかも減らないなら書き込みがディスクに降りられていない最中です。Slab が異常に大きければカーネルオブジェクトのリークを疑います。プロセスごとの実際の使用量はRSSが共有ページを二重に数えてしまうため、可能ならPSSを見てください。

sudo grep -H '^Pss:' /proc/1234/smaps_rollup

5. ディスクが埋まったとき — 容量とinode

ディスク不足は二種類あります。ブロック不足inode不足 です。df -h だけを見て「余裕がありますよ」と答えたのに、実際にはinodeが枯渇していたというケースは珍しくありません。

df -h
df -i

df -iIUse% が100パーセントなら、容量が残っていても新しいファイルを作れません。セッションファイルやメールキューのように 小さなファイルが数百万個たまるディレクトリ が原因である場合がほとんどです。

大きなディレクトリを探すときは、一つのファイルシステムの中だけを再帰するように制限するのが安全です。

sudo du -x -h --max-depth=1 /var | sort -h | tail -20

-x は他のファイルシステムに移らないようにします。これがないと /proc やネットワークマウントまで走査してしまい、かなり時間がかかります。

dfdu の値が大きく違うなら、削除されたけれどまだ開かれているファイル が原因です。ファイルを消しても、そのファイルを開いたプロセスが生きていれば領域は返却されません。

sudo lsof +L1
sudo lsof -nP +L1 | awk '{print $1, $2, $7, $9}' | sort -k3 -n -r | head

+L1 はリンク数が1より小さい、つまりすでにunlinkされた開いているファイルを列挙します。解決策は該当プロセスにログ再オープンのシグナルを送るか、再起動することです。詳しい原理はこのシリーズの ファイルディスクリプタとinodeガイド で扱います。


6. I/O — 遅いディスクの証拠を探す

iostat -xz 1 3

-x は拡張統計、-z は活動のないデバイスを省略します。最初のレポートは起動以降の統計なので、-y で省略するか2番目のレポートから読みます。

見るべき列は次のとおりです。

  • r_await / w_await: リクエストがキューで待った時間まで含めた平均応答時間(ミリ秒)。NVMeで1桁ミリ秒を超えるならおかしく、回転ディスクは10から20までは正常範囲です
  • aqu-sz: 平均キュー長。1を大きく超えるとデバイスがリクエストを消化できていない最中です。
  • rareq-sz / wareq-sz: リクエストの平均サイズ(KiB)。小さなランダムI/Oなのか大きなシーケンシャルI/Oなのかを区別してくれます。
  • %util: このデバイスにI/Oが発行されていた時間の比率。

%util は必ず注意しなければなりません。manページが明示的に警告しています。リクエストを直列で処理するデバイスでは100パーセントが飽和を意味しますが、RAIDアレイや最新のSSDのように並列処理するデバイスでは100パーセントでも性能の限界ではありません。この場合の判断基準は %util ではなく await です。

どのプロセスがI/Oを生んでいるのかは pidstat -d で見ます。

pidstat -d 1 5

kB_rd/skB_wr/s がプロセスごとの読み書きで、iodelay はブロックI/Oの遅延をクロックティック単位で見せてくれます。iotop がインストールされていれば対話的に見るほうが楽です。

sudo iotop -oPa

7. ネットワーク — ポート、キュー、そして再送

netstat はnet-toolsパッケージの遺物であり、最新ディストリビューションの標準は ss です。

ss -tulpn
ss -tan state established | head
ss -s
  • -t TCP、-u UDP、-l リッスンのみ、-a すべて、-n 名前解決をしない、-p ソケットを使っているプロセスを表示。
  • -p でプロセス名を見るには通常root権限が必要です。

Recv-QSend-Q はソケットの状態によって意味が変わります。リッスンソケットでの Recv-Q はacceptを待つ完了キューの長さ であり、Send-Q はバックログの最大値です。リッスンソケットの Recv-Q が埋まり続けているなら、アプリケーションがacceptに追いついていない最中です。確立された接続では、それぞれまだ読まれていない受信データと、まだ確認されていない送信データを意味します。ただし、この2つの列の意味は man7.org で公開されている ss マニュアルの本文には明記されておらず、iproute2 の実装動作に基づくものです。判断の根拠にする前に、インストールされている iproute2 バージョンの man ページで一度確認する ほうが安全です。

経路の問題なのかアプリケーションの問題なのかは、レイヤーを分けて確認します。

ip -brief addr
ip route get 10.0.3.14
ping -c 4 10.0.3.14
mtr -rwc 20 10.0.3.14
curl -sS -o /dev/null -w 'dns:%{time_namelookup} conn:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n' https://example.com

curl のタイミング変数は、どの段階が遅いのかを1行で見せてくれます。DNSの段階が遅ければ名前解決の問題、time_connect が遅ければ経路かファイアウォール、time_starttransfer だけが遅ければサーバーアプリケーションです。

TCP再送が多いかどうかを確認します。

nstat -az | grep -i -E 'retrans|drop|overflow'
ss -ti state established | grep -E 'retrans|rtt' | head

ListenOverflows または ListenDrops が増えているなら、バックログがあふれている最中です。


8. ログ — 時間範囲を先に絞る

ログを最初から読まないでください。障害時刻の前後5分だけ を見ます。

journalctl --since '2026-08-15 14:10' --until '2026-08-15 14:30' -p err
journalctl -u nginx.service -n 200 --no-pager
journalctl -u nginx.service -f
journalctl -k -b -1 -p warning
journalctl -g 'timeout|refused|denied' --since today
  • -p err はerr以上の優先度だけを見ます。優先度の名前はemerg、alert、crit、err、warning、notice、info、debugの順です。
  • -b -1 は直前の起動のログです。サーバーが突然再起動した場合、ここに原因が残っています。
  • -g はMESSAGEフィールドに正規表現を適用します。

起動の一覧と再起動原因の確認はこうします。

journalctl --list-boots
last -x reboot shutdown | head

last -x に正常終了の記録がなく再起動だけがあるなら、カーネルパニックや電源の問題、ハイパーバイザーによる強制再起動を疑います。ログのパイプライン自体を設計する方法は Linuxログ運用ガイド で扱います。


9. 止まっているように見えるプロセスを掘り下げる

応答のないプロセスは三つのうちのどれかです。CPUを燃やしている最中 か、何かを待っている最中 か、ロックに引っかかっている最中 です。

まずカーネルが報告する待機地点を見ます。これは副作用のない読み取り操作です。

cat /proc/1234/status | grep -E 'State|Threads|voluntary'
sudo cat /proc/1234/stack
sudo cat /proc/1234/wchan; echo
ls -l /proc/1234/fd | head

StateD (disk sleep) なら中断不可待ちです。この状態のプロセスはSIGKILLでも死にません。待っているリソース(ほとんどはストレージかNFS)が応答して初めて解けます。

システムコールのレベルを見る必要があるなら strace を付けますが、本番環境ではプロセスを大きく遅くするという点 を必ず認識したうえで、短く使ってください。

sudo strace -f -p 1234 -tt -T -e trace=network,file 2>&1 | head -50
sudo strace -c -f -p 1234

-c はサマリーだけを出すので負荷が相対的に低く、どのシステムコールで時間を使っているのかを一目で見せてくれます。strace が付かない場合は、カーネルのptrace制限設定が理由かもしれません。

cat /proc/sys/kernel/yama/ptrace_scope

値が1以上なら同じユーザーでも任意のプロセスに付くことはできず、rootが必要です。

ファイルロックのせいで止まっている場合もよくあります。

cat /proc/locks | head
sudo lsof /var/lib/myapp/data.db

10. 再現しない障害を捕まえる常時収集

最も多い失敗は「あのときログを残していなかった」です。瞬間的な負荷は人がログインする前に終わってしまうので、平常時から収集が回っている必要があります

sar はこの用途のために作られました。デフォルトの収集周期はディストリビューションの設定によって異なり、通常は10分間隔です。

sar -u -f /var/log/sa/sa15
sar -r -s 14:00:00 -e 15:00:00
sar -n DEV -s 14:00:00 -e 15:00:00
sar -q

-f で特定の日付のファイルを指定します。ファイルのパスはRHEL系が /var/log/sa/、Debian系が /var/log/sysstat/ と異なります。

しきい値を超えたときだけスナップショットを残す簡単な方式も有効です。次は負荷がしきい値を超えたらプロセス一覧をファイルに残す例です。

#!/usr/bin/env bash
set -euo pipefail
THRESHOLD=20
LOAD=$(awk '{print int($1)}' /proc/loadavg)
if [ "$LOAD" -ge "$THRESHOLD" ]; then
  TS=$(date +%Y%m%d-%H%M%S)
  OUT="/var/log/spike-$TS.txt"
  {
    uptime
    ps -eo pid,stat,pcpu,pmem,etime,args --sort=-pcpu | head -30
    ss -s
    vmstat 1 3
  } > "$OUT"
fi

このスクリプトを1分周期のcronやsystemdタイマーに仕掛けておけば、次に瞬間的な負荷が来たときに人がいなくても証拠が残ります。タイマーの書き方は systemdタイマー完全攻略 を参考にしてください。

最後に、診断中に実行するコマンドが障害を大きくしないよう 注意します。ルートで du -x-x を付け忘れて回したり、すでにI/Oが飽和したディスクに find / の全体スキャンをかけたりするのは状況を悪化させます。ディスクがすでに100パーセント使用中のときは、読み取り作業も列に並ばなければならないという点を覚えておいてください。


クイズ: 理解度を確認しましょう

クイズ1: ロードアベレージが40なのにtopのCPU使用率は全部合わせて15パーセントです。何を最初に確認すべきでしょうか

答え: 中断不可待ち(D状態)のプロセスとディスクI/Oを確認します

解説: Linuxのロードアベレージは実行可能(R)状態だけでなく、中断不可待ち(D)状態のプロセスも含みます。CPUが暇なのに負荷だけが高いなら、ほとんどはストレージやNFSの応答待ちが原因です。順番は次のとおりです。

ps -eo pid,stat,wchan:20,args --sort=-pcpu | awk '$2 ~ /D/'
iostat -xz 1 3
vmstat 1 5

iostatawait が大きく、vmstatb 列が大きければストレージのボトルネックが確定します。

クイズ2: df -hでは余裕が30パーセントなのに、アプリケーションがファイルを作れずに失敗します。原因の候補二つは何でしょうか

答え: inodeの枯渇、そしてそのパスが実際には別の(いっぱいになった)ファイルシステムであるか、クォータに引っかかっている場合です

解説: ブロックの余裕とinodeの余裕は別物です。小さなファイルが数百万個たまると、容量が残っていてもinodeが先に尽きます。

df -i
df -h /var/lib/myapp
mount | grep myapp

df にパスを直接渡して、そのパスがどのファイルシステムに属するのかをまず確認することが重要です。/var が別マウントである場合はよくあります。

クイズ3: ログファイルを消したのにdfの使用量がそのままです。なぜで、どう解決しますか

答え: ファイルを開いたプロセスがまだ生きていてinodeが解放されていないからです。該当プロセスにファイルを開き直させて初めて領域が返却されます

解説: unlinkはディレクトリエントリだけを消します。開いているファイルディスクリプタが残っている限り、データブロックは維持されます。

sudo lsof -nP +L1 | head
sudo systemctl reload rsyslog

ログの場合はたいてい再オープンを引き起こすreloadで十分です。プロセスを殺すのは最後の手段です。そもそもこういう状況を作らないためには、logrotatecopytruncate ではなく postrotate フックで再オープンのシグナルを送るように設定してください。

クイズ4: iostatで%utilが100パーセントと出ます。ディスクが飽和だと結論づけてよいでしょうか

答え: いいえ。リクエストを並列処理するデバイスでは100パーセントでも限界ではありません

解説: iostatのmanページは、RAIDアレイや最新のSSDのようにリクエストを並列で処理するデバイスではこの値が性能の限界を反映しない、と明記しています。%util は「このデバイスにリクエストが一つでも発行されていた時間の比率」でしかありません。判断は r_awaitw_awaitaqu-sz で行うべきです。応答時間が普段の水準なら100パーセントでも問題ではありません。

クイズ5: プロセスにSIGKILLを送ったのに死にません。考えられる状況と確認方法は何でしょうか

答え: プロセスがD状態(中断不可待ち)であるか、すでにゾンビ(Z)になっています

解説: SIGKILLはカーネルが強制的に処理しますが、D状態ではシグナルの配送自体が遅延します。カーネルが待っているリソース(ストレージ、NFSサーバー)が応答して初めて解けます。ゾンビはすでに死んだプロセスであり、残っているのは親が回収していない終了状態だけなので、殺す対象がありません。親を処理して初めて消えます。

ps -o pid,ppid,stat,wchan:24,args -p 1234
sudo cat /proc/1234/stack
クイズ6: デプロイ直後に応答の遅延が生じました。アプリケーションの問題かネットワークの問題かを一度のコマンドで絞るにはどうしますか

答え: curlのタイミング変数で段階を分解します

解説: どの区間で時間が消費されているのかを分ければ、調査範囲が即座に狭まります。

curl -sS -o /dev/null -w 'dns:%{time_namelookup} conn:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n' https://api.example.com/health

time_connect までは正常なのに time_starttransfer だけが大きければ、ネットワークは無実でサーバーが応答を作るのに時間がかかっているということです。逆に time_namelookup が大きければ、名前解決の経路から見るべきです。


おわりに

障害対応が上手な人とそうでない人の違いは、知っているコマンドの数ではありません。このコマンドの結果で何を除外できるのか を毎回意識しているかどうかの違いです。

vmstat を打つ前に「ここで wa が低ければディスクを消す」とあらかじめ決めておけば、出力が出た瞬間に次の行動が決まります。そうしなければ、同じ画面を三回見ても何一つ絞り込めません。

この記事のコマンド一覧を社内wikiにそのまま移すのではなく、最初の60秒のブロックをスクリプト一つにまとめて全サーバーに配布してください。障害が起きたときにそのスクリプト一つを実行するほうが、9個のコマンドを思い出すよりはるかに速いです。


参考資料


関連記事