この記事について
この記事は、実務でサーバーを監視・トラブルシューティングするためのLinuxコマンド完全ガイドです。
「サーバーが重い」「なんか遅い」と言われたときに、何を見て、どう判断するかを体系的にまとめました。
対象読者
- サーバー運用に携わるエンジニア
- 「top以外よく分からない」という人
- 障害対応で慌てたくない人
- インフラの基礎を固めたい人
この記事で扱うこと
| カテゴリ | 内容 |
|---|---|
| CPU | 負荷の見方、ボトルネックの特定 |
| メモリ | 使用量、スワップ、OOM |
| ディスク | 容量、I/O、ボトルネック |
| ネットワーク | コネクション、帯域、パケット |
| プロセス | 特定、追跡、強制終了 |
| ログ | 効率的な調査方法 |
監視の基本原則
まず全体像を掴む
障害対応で最も重要なのは、いきなり細部を見ないこと。
flowchart TB
Start["🚨 障害・パフォーマンス問題発生"] --> Step1["1️⃣ 全体像を掴む<br/>何がおかしいか?<br/><code style='color: white'>uptime</code> / <code style='color: white'>top</code>"]
Step1 --> Step2["2️⃣ ボトルネックを特定する<br/>どこがおかしいか?<br/>CPU / メモリ / ディスク / ネットワーク"]
Step2 --> Step3["3️⃣ 原因を深掘りする<br/>なぜおかしいか?<br/>プロセス特定 / ログ調査"]
Step3 --> Step4["4️⃣ 対処する<br/>どう直すか?<br/>プロセス再起動 / 設定変更 / リソース増強"]
Step4 --> End["✅ 問題解決"]
style Start fill:#ffebee
style End fill:#e8f5e9
style Step1 fill:#e3f2fd
style Step2 fill:#e3f2fd
style Step3 fill:#e3f2fd
style Step4 fill:#e3f2fd
リソースの4大要素
サーバーの問題は、ほぼこの4つに集約されます:
flowchart TB
Problem["⚠️ サーバー問題発生"] --> Check{どのリソースが<br/>ボトルネック?}
Check -->|CPU| CPU["💻 CPU枯渇<br/>━━━━━━<br/>症状:処理が遅い、タイムアウト<br/>確認:<code style='color: white'>uptime</code> / <code style='color: white'>top</code><br/>対策:プロセス最適化、スケールアップ"]
Check -->|メモリ| MEM["🧠 メモリ枯渇<br/>━━━━━━<br/>症状:OOM Killer、スワップで激遅<br/>確認:<code style='color: white'>free -h</code> / <code style='color: white'>vmstat</code><br/>対策:メモリ増設、プロセス削減"]
Check -->|ディスク| DISK["💾 ディスク枯渇<br/>━━━━━━<br/>症状:書き込み失敗、I/O待ち<br/>確認:<code style='color: white'>df -h</code> / <code style='color: white'>iostat</code><br/>対策:容量確保、高速ディスク"]
Check -->|ネットワーク| NET["🌐 ネットワーク枯渇<br/>━━━━━━<br/>症状:接続失敗、タイムアウト<br/>確認:<code style='color: white'>ss -s</code> / <code style='color: white'>nethogs</code><br/>対策:帯域増強、接続数制限"]
style Problem fill:#ffebee
style CPU fill:#fff3e0
style MEM fill:#fff3e0
style DISK fill:#fff3e0
style NET fill:#fff3e0
Part 1: CPU監視
CPUの基本概念
Load Average(負荷平均)とは
Load Average は、「CPUの待ち行列の長さ」を示します。
$ uptime
14:30:01 up 30 days, 2:15, 3 users, load average: 1.50, 2.00, 1.80
^^^^ ^^^^ ^^^^
1分 5分 15分
Load Averageの読み方
| コア数 | 正常 | 要注意 | 危険 |
|---|---|---|---|
| 1コア | < 1.0 | 1.0〜2.0 | > 2.0 |
| 4コア | < 4.0 | 4.0〜8.0 | > 8.0 |
| 8コア | < 8.0 | 8.0〜16.0 | > 16.0 |
目安: Load Average ÷ CPUコア数 < 1.0 なら正常
# CPUコア数の確認
$ nproc
4
# または
$ grep -c processor /proc/cpuinfo
4
uptime - 最速の状態確認
$ uptime
14:30:01 up 30 days, 2:15, 3 users, load average: 0.50, 0.80, 0.75
| 項目 | 意味 |
|---|---|
14:30:01 |
現在時刻 |
up 30 days |
起動してからの時間 |
3 users |
ログイン中のユーザー数 |
load average |
1分、5分、15分の負荷平均 |
負荷の傾向を読む
flowchart TB
Check["<code style='color: white'>uptime</code>で確認"] --> Pattern{Load Averageの<br/>パターンは?}
Pattern -->|"1分 > 5分 > 15分"| Rising["📈 急上昇中<br/>━━━━━━<br/>例:8.00, 2.00, 1.00<br/><br/>🔍 直近で何かが起きた<br/>・新しいプロセスが起動<br/>・突発的なアクセス増<br/>・バッチ処理開始"]
Pattern -->|"1分 < 5分 < 15分"| Falling["📉 収束中<br/>━━━━━━<br/>例:1.00, 2.00, 8.00<br/><br/>✅ 過去に問題があったが<br/>現在は落ち着いている<br/>・問題は自然解決<br/>・対処が効いている"]
Pattern -->|"1分 ≒ 5分 ≒ 15分"| Stable["📊 定常的に高い<br/>━━━━━━<br/>例:4.00, 4.00, 4.00<br/><br/>⚠️ 慢性的な問題<br/>・常時負荷が高い<br/>・リソース不足<br/>・要チューニング or 増強"]
style Rising fill:#ffebee
style Falling fill:#e8f5e9
style Stable fill:#fff3e0
top - リアルタイム監視の王道
$ top
画面の見方
top - 14:30:01 up 30 days, 2:15, 3 users, load average: 0.50, 0.80, 0.75
Tasks: 200 total, 1 running, 199 sleeping, 0 stopped, 0 zombie
%Cpu(s): 5.0 us, 2.0 sy, 0.0 ni, 92.0 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 16000.0 total, 8000.0 free, 6000.0 used, 2000.0 buff/cache
MiB Swap: 2000.0 total, 2000.0 free, 0.0 used. 9500.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 mysql 20 0 2.0g 500m 20m S 15.0 3.1 100:00.00 mysqld
5678 www-data 20 0 300m 100m 50m S 5.0 0.6 50:00.00 php-fpm
CPU行の詳細
%Cpu(s): 5.0 us, 2.0 sy, 0.0 ni, 92.0 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
^^^^ ^^^^ ^^^^ ^^^^^ ^^^^ ^^^^ ^^^^ ^^^^
| 項目 | 意味 | 高いとき |
|---|---|---|
| us (user) | ユーザープロセス | アプリが重い |
| sy (system) | カーネル処理 | I/O多い、コンテキストスイッチ多い |
| ni (nice) | nice値変更プロセス | 優先度下げたプロセスが動いている |
| id (idle) | アイドル | 低いと忙しい |
| wa (wait) | I/O待ち | ディスクがボトルネック |
| hi (hardware interrupt) | ハードウェア割り込み | デバイスの問題 |
| si (software interrupt) | ソフトウェア割り込み | ネットワーク処理多い |
| st (steal) | VM盗まれた時間 | ホストが過負荷(クラウドで重要) |
重要な指標
wa(I/O wait)が高い場合
ディスクI/Oがボトルネック
→ iostatで詳細確認
→ 遅いクエリ、ログ出力過多などを疑う
st(steal)が高い場合
VMホストが過負荷(クラウド環境でよくある)
→ インスタンスタイプの変更を検討
→ クラウドプロバイダーに問い合わせ
topの便利なキー操作
| キー | 動作 |
|---|---|
1 |
CPU別表示(マルチコア環境で便利) |
M |
メモリ使用量でソート |
P |
CPU使用量でソート |
k |
プロセスをkill |
c |
コマンドライン全体表示 |
H |
スレッド表示 |
q |
終了 |
htop - より見やすいtop
$ htop
htopは、topの高機能版です。
htopの利点
- カラー表示で見やすい
- マウス操作可能
- 横スクロールでコマンドライン全体が見える
- プロセスツリー表示(
F5) - 検索機能(
F3)
インストール
# Debian/Ubuntu
sudo apt install htop
# CentOS/RHEL
sudo yum install htop
# macOS
brew install htop
vmstat - システム統計の定番
$ vmstat 1 5 # 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
1 0 0 800000 50000 200000 0 0 5 10 100 200 5 2 92 1 0
2 0 0 795000 50000 200000 0 0 0 20 150 250 10 3 85 2 0
各項目の意味
procs(プロセス)
| 項目 | 意味 | 注意点 |
|---|---|---|
| r | 実行待ちプロセス数 | CPUコア数より多いと過負荷 |
| b | I/O待ちプロセス数 | 0以外はディスクボトルネック |
memory(メモリ)
| 項目 | 意味 |
|---|---|
| swpd | 使用中のスワップ |
| free | 空きメモリ |
| buff | バッファキャッシュ |
| cache | ページキャッシュ |
swap(スワップ)
| 項目 | 意味 | 注意点 |
|---|---|---|
| si | スワップイン | 0以外は危険信号 |
| so | スワップアウト | 0以外は危険信号 |
cpu
topと同じ。waが高いとI/O待ち。
mpstat - CPU別の詳細統計
$ mpstat -P ALL 1 # 全CPU、1秒間隔
CPU %usr %nice %sys %iowait %irq %soft %steal %idle
all 5.00 0.00 2.00 1.00 0.00 0.00 0.00 92.00
0 10.00 0.00 3.00 2.00 0.00 0.00 0.00 85.00
1 2.00 0.00 1.00 0.00 0.00 0.00 0.00 97.00
2 5.00 0.00 2.00 1.00 0.00 0.00 0.00 92.00
3 3.00 0.00 2.00 1.00 0.00 0.00 0.00 94.00
使いどころ
- 特定のCPUだけ100%になっていないか確認
- シングルスレッドアプリのボトルネック発見
Part 2: メモリ監視
メモリの基本概念
Linuxのメモリ管理
Linuxは、空きメモリを積極的にキャッシュに使います。
「空きメモリが少ない!」
→ 実はキャッシュとして有効活用されているだけかも
→ 本当に危険なのは「利用可能メモリ」が少ないとき
メモリの種類
| 種類 | 説明 |
|---|---|
| Used | 実際に使用中 |
| Free | 完全に未使用 |
| Buffers | ブロックデバイスのキャッシュ |
| Cached | ファイルのキャッシュ |
| Available | 実際に利用可能な量(これを見る) |
free - メモリ使用状況の確認
$ free -h # 人間が読みやすい形式
total used free shared buff/cache available
Mem: 16Gi 6.0Gi 2.0Gi 500Mi 8.0Gi 9.0Gi
Swap: 2.0Gi 0B 2.0Gi
読み方のポイント
重要なのは「available」列!
available = free + (解放可能なbuff/cache)
この例では:
- total: 16GB
- available: 9GB(実際に使える量)
- → まだ余裕あり
危険な状態
total used free shared buff/cache available
Mem: 16Gi 15Gi 100Mi 500Mi 900Mi 500Mi
Swap: 2.0Gi 1.5Gi 500Mi
^^^^ ^^^^
スワップ使用中 利用可能が少ない
警告サイン:
availableが総メモリの10%以下Swap usedが0以外
/proc/meminfo - 詳細なメモリ情報
$ cat /proc/meminfo
MemTotal: 16384000 kB
MemFree: 2000000 kB
MemAvailable: 9000000 kB
Buffers: 500000 kB
Cached: 7000000 kB
SwapCached: 0 kB
Active: 8000000 kB
Inactive: 5000000 kB
...
よく見る項目
| 項目 | 意味 |
|---|---|
| MemTotal | 総物理メモリ |
| MemAvailable | 利用可能メモリ |
| SwapTotal | スワップ総量 |
| SwapFree | スワップ空き |
| Dirty | ディスク書き込み待ちのページ |
| Slab | カーネルのデータ構造用 |
スワップの監視
スワップが使われている=危険信号
# スワップ使用状況
$ swapon --show
NAME TYPE SIZE USED PRIO
/dev/sda2 partition 2G 500M -2
# どのプロセスがスワップを使っているか
$ for pid in /proc/[0-9]*; do
awk '/VmSwap/{if($2>0)print FILENAME,$0}' $pid/status 2>/dev/null
done | sort -k3 -rn | head -10
vmstatでスワップ活動を見る
$ vmstat 1
---swap--
si so
0 0 ← 正常
100 200 ← スワップイン/アウトが発生中(危険)
si/soが継続的に0以外: メモリ不足でスワップが常用されている
OOM Killer
OOM Killerとは
メモリが枯渇すると、Linuxカーネルは OOM Killer を発動し、プロセスを強制終了します。
OOM Killerのログを確認
$ dmesg | grep -i "out of memory"
$ dmesg | grep -i "killed process"
# または
$ journalctl -k | grep -i oom
OOM Killerの発動例
Out of memory: Killed process 1234 (java) total-vm:8000000kB, anon-rss:4000000kB
特定のプロセスをOOM Killerから守る
# OOMスコアを確認(高いほど殺されやすい)
$ cat /proc/1234/oom_score
# OOM Killerから保護(-1000 = 絶対に殺さない)
$ echo -1000 > /proc/1234/oom_score_adj
Part 3: ディスク監視
ディスクの基本概念
2つの観点
| 観点 | 内容 | 問題 |
|---|---|---|
| 容量 | どれだけ使っているか | 満杯になると書き込み失敗 |
| I/O性能 | どれだけ速いか | 遅いとシステム全体が遅くなる |
df - ディスク容量の確認
$ df -h # 人間が読みやすい形式
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 35G 15G 70% /
/dev/sda2 100G 80G 20G 80% /var
tmpfs 7.8G 500M 7.3G 7% /dev/shm
重要なポイント
# 使用率が高いものだけ表示
$ df -h | awk '$5 > 80 {print}'
警告ライン:
- 80%: 警告
- 90%: 危険
- 95%以上: 緊急対応
inode使用量も確認
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 3276800 500000 2776800 16% /
小さいファイルが大量にある場合、inodeが先に枯渇することも
du - ディレクトリ別の使用量
# カレントディレクトリ直下の使用量
$ du -sh *
# 大きいディレクトリを探す
$ du -h --max-depth=1 / 2>/dev/null | sort -hr | head -20
# 特定ディレクトリ内で大きいファイルを探す
$ find /var/log -type f -size +100M -exec ls -lh {} \;
よく容量を食う場所
/var/log # ログファイル
/tmp # 一時ファイル
/var/lib/docker # Dockerイメージ・コンテナ
/home # ユーザーデータ
iostat - ディスクI/O統計
$ iostat -xz 1 # 拡張統計、1秒間隔
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util
sda 10.00 50.00 100.00 500.00 0.00 5.00 15.00
sdb 5.00 100.00 50.00 2000.00 0.00 10.00 80.00
重要な指標
| 指標 | 意味 | 危険ライン |
|---|---|---|
| r/s | 1秒あたりの読み取り回数 | - |
| w/s | 1秒あたりの書き込み回数 | - |
| await | I/O待ち時間(ms) | > 20ms |
| %util | ディスク使用率 | > 80% |
await(I/O待ち時間)の目安
| デバイス | 正常 | 要注意 | 危険 |
|---|---|---|---|
| SSD | < 1ms | 1-5ms | > 5ms |
| HDD | < 10ms | 10-20ms | > 20ms |
| クラウドディスク | 変動大 | - | - |
%utilが100%に張り付いている場合
ディスクが飽和状態
→ I/Oを減らすか、高速なディスクに変更
→ 遅いクエリ、過剰なログ出力を疑う
iotop - プロセス別I/O使用量
$ sudo iotop -o # I/Oを使っているプロセスのみ表示
Total DISK READ: 10.00 M/s | Total DISK WRITE: 50.00 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1234 be/4 mysql 5.00 M/s 30.00 M/s 0.00 % 80.00 % mysqld
5678 be/4 root 1.00 M/s 10.00 M/s 0.00 % 15.00 % rsync
どのプロセスがI/Oを使っているか一目瞭然
lsof - 開いているファイルの確認
# 特定ディレクトリを開いているプロセス
$ lsof +D /var/log
# 削除されたけど開かれているファイル(容量を食い続ける)
$ lsof | grep deleted
# 特定プロセスが開いているファイル
$ lsof -p 1234
削除したのに容量が減らない問題
$ lsof | grep deleted
mysqld 1234 mysql 10u REG 8,1 5000000000 /var/log/mysql.log (deleted)
^^^^^^^^^^
5GB食っている
# プロセスを再起動するか、ファイルディスクリプタを閉じる
Part 4: ネットワーク監視
ネットワークの基本概念
よくある問題
| 問題 | 症状 |
|---|---|
| 接続数過多 | 新規接続が拒否される |
| 帯域不足 | 転送が遅い |
| パケットロス | 通信が不安定 |
| DNS問題 | 名前解決が遅い・失敗 |
ss - 接続状態の確認(netstatの後継)
# 全接続を表示
$ ss -tuln
# 確立済み接続を表示
$ ss -t state established
# 特定ポートへの接続
$ ss -t dst :3306
接続状態の確認
$ ss -s
Total: 1500
TCP: 1200 (estab 800, closed 200, orphaned 50, timewait 150)
状態別の意味
| 状態 | 意味 | 多いと |
|---|---|---|
| ESTABLISHED | 確立済み | 正常 |
| TIME_WAIT | 終了待ち | 短時間接続が多い |
| CLOSE_WAIT | 相手が閉じた | アプリがcloseしてない |
| SYN_RECV | SYN受信済み | SYN flood攻撃の可能性 |
ポート別の接続数を確認
# ポート別の接続数
$ ss -t state established | awk '{print $4}' | cut -d: -f2 | sort | uniq -c | sort -rn | head
500 3306 # MySQL
300 80 # HTTP
100 443 # HTTPS
IPアドレス別の接続数
# 接続元IP別の接続数(DDoS調査など)
$ ss -t state established | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
100 192.168.1.100
50 192.168.1.101
30 10.0.0.50
netstat - 従来のネットワーク統計
# 接続状態の統計
$ netstat -s
# LISTEN中のポート
$ netstat -tlnp
TCP統計の重要項目
$ netstat -s | grep -E "(retransmit|overflow|drop)"
1234 segments retransmitted # 再送が多いとネットワーク品質に問題
56 times the listen queue of a socket overflowed # 接続キューあふれ
lsof - ネットワーク接続の詳細
# 特定ポートを使っているプロセス
$ lsof -i :3306
# 特定プロセスのネットワーク接続
$ lsof -i -a -p 1234
# 特定ホストへの接続
$ lsof -i @192.168.1.100
tcpdump - パケットキャプチャ
# 特定ポートのトラフィック
$ sudo tcpdump -i eth0 port 80
# 特定ホストとの通信
$ sudo tcpdump -i eth0 host 192.168.1.100
# ファイルに保存(後でWiresharkで分析)
$ sudo tcpdump -i eth0 -w capture.pcap
# HTTPリクエストの内容を表示
$ sudo tcpdump -i eth0 -A port 80
よく使うフィルタ
# SYNパケットのみ(接続開始)
$ sudo tcpdump 'tcp[tcpflags] & tcp-syn != 0'
# RSTパケット(接続拒否)
$ sudo tcpdump 'tcp[tcpflags] & tcp-rst != 0'
# 特定サイズ以上のパケット
$ sudo tcpdump 'greater 1000'
ip / ifconfig - インターフェース情報
# インターフェース一覧と統計
$ ip -s link
# IPアドレス確認
$ ip addr
# ルーティングテーブル
$ ip route
エラー統計の確認
$ ip -s link show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
RX: bytes packets errors dropped overrun mcast
1000000000 5000000 0 0 0 0
TX: bytes packets errors dropped carrier collsns
500000000 2500000 0 0 0 0
↑ ↑
エラーやドロップが増えていたら問題
帯域使用量の確認
iftop - リアルタイム帯域モニタ
$ sudo iftop -i eth0
nethogs - プロセス別帯域使用量
$ sudo nethogs eth0
PID USER PROGRAM DEV SENT RECEIVED
1234 mysql mysqld eth0 10.00 MB 5.00 MB
5678 www-data nginx eth0 5.00 MB 20.00 MB
nload - シンプルな帯域モニタ
$ nload eth0
Part 5: プロセス監視
ps - プロセス一覧
基本的な使い方
# 全プロセス(フル表示)
$ ps auxf
# 特定ユーザーのプロセス
$ ps -u mysql
# 特定コマンドのプロセス
$ ps aux | grep nginx
# 親子関係をツリー表示
$ ps auxf
出力の意味
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
mysql 1234 5.0 3.0 2000000 500000 ? Ssl Jan01 100:00 mysqld
^^^^ ^^^ ^^^ ^^^^^^ ^^^^^^ ^^^^
│ │ │ │ │ └─ プロセス状態
│ │ │ │ └─ 実メモリ使用量
│ │ │ └─ 仮想メモリサイズ
│ │ └─ メモリ使用率
│ └─ CPU使用率
└─ プロセスID
STAT(プロセス状態)の意味
| 状態 | 意味 |
|---|---|
| R | 実行中 |
| S | スリープ(割り込み可能) |
| D | スリープ(割り込み不可、I/O待ち) |
| Z | ゾンビ |
| T | 停止 |
D状態が多い → I/Oボトルネック
プロセスの特定テクニック
CPU使用量トップ10
$ ps aux --sort=-%cpu | head -11
メモリ使用量トップ10
$ ps aux --sort=-%mem | head -11
特定コマンドのプロセス数
$ pgrep -c nginx
8
プロセスの起動時刻
$ ps -p 1234 -o pid,lstart,cmd
PID STARTED CMD
1234 Mon Jan 1 00:00:00 2024 /usr/sbin/mysqld
pgrep / pkill - プロセスの検索と終了
# プロセス検索
$ pgrep -l nginx
1234 nginx
1235 nginx
# プロセスの詳細情報
$ pgrep -a nginx
1234 nginx: master process
1235 nginx: worker process
# プロセス終了(SIGTERM)
$ pkill nginx
# 強制終了(SIGKILL)
$ pkill -9 nginx
プロセスの詳細調査
/proc ファイルシステム
# プロセスのコマンドライン
$ cat /proc/1234/cmdline | tr '\0' ' '
# プロセスの環境変数
$ cat /proc/1234/environ | tr '\0' '\n'
# プロセスの開いているファイル
$ ls -la /proc/1234/fd
# プロセスのメモリマップ
$ cat /proc/1234/maps
# プロセスのステータス
$ cat /proc/1234/status
strace - システムコールのトレース
# プロセスのシステムコールを追跡
$ strace -p 1234
# 新規プロセスを追跡
$ strace -f -e trace=network curl example.com
# ファイルアクセスのみ追跡
$ strace -e trace=file ls
Part 6: ログ調査
journalctl - systemdのログ
# 全ログ
$ journalctl
# 特定サービスのログ
$ journalctl -u nginx
# リアルタイム監視
$ journalctl -f
# 今日のログ
$ journalctl --since today
# エラーレベル以上
$ journalctl -p err
# カーネルログ
$ journalctl -k
時間指定
# 特定時間範囲
$ journalctl --since "2024-01-01 10:00:00" --until "2024-01-01 11:00:00"
# 直近1時間
$ journalctl --since "1 hour ago"
ログファイルの効率的な調査
tail - リアルタイム監視
# リアルタイム監視
$ tail -f /var/log/nginx/error.log
# 複数ファイル同時監視
$ tail -f /var/log/nginx/*.log
# 最後の100行
$ tail -n 100 /var/log/syslog
grep - パターン検索
# エラーを検索
$ grep -i error /var/log/nginx/error.log
# 前後の行も表示
$ grep -B 5 -A 5 "error" /var/log/nginx/error.log
# 複数パターン
$ grep -E "(error|warning|critical)" /var/log/syslog
# 特定パターンを除外
$ grep -v "健全性チェック" /var/log/nginx/access.log
awk - ログの集計
# アクセスログからステータスコード集計
$ awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
10000 200
1000 304
500 404
100 500
# IPアドレス別アクセス数
$ awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
less - 大きいログの閲覧
$ less /var/log/syslog
# 検索: /パターン
# 次の検索結果: n
# 前の検索結果: N
# 末尾に移動: G
# 先頭に移動: g
dmesg - カーネルログ
# カーネルログ表示
$ dmesg
# 人間が読みやすい時刻表示
$ dmesg -T
# エラーレベル以上
$ dmesg --level=err,warn
# リアルタイム監視
$ dmesg -w
よく見るカーネルメッセージ
# OOM Killer
$ dmesg | grep -i "out of memory"
# ディスクエラー
$ dmesg | grep -i "error"
# ネットワークエラー
$ dmesg | grep -i "eth0"
Part 7: 実践的なトラブルシューティング
シナリオ1: 「サーバーが重い」
調査フロー
flowchart TB
Start["🐌 サーバーが重い"] --> Step1["1️⃣ 全体像を把握<br/><code style='color: white'>uptime</code>"]
Step1 --> Load["Load Average確認"]
Load --> Step2["2️⃣ 原因を切り分け<br/><code style='color: white'>top</code>"]
Step2 --> Check{何が高い?}
Check -->|"%CPU が高い"| CPU["3a. CPU使用率が高い<br/>━━━━━━<br/><code style='color: white'>ps aux --sort=-%cpu | head -5</code>"]
Check -->|"%wa が高い"| IOWAIT["3b. I/O wait が高い<br/>━━━━━━<br/><code style='color: white'>iostat -xz 1</code><br/><code style='color: white'>iotop -o</code>"]
Check -->|"%st が高い"| STEAL["3c. steal が高い<br/>━━━━━━<br/>VMホストが過負荷<br/>(クラウド環境)"]
CPU --> CPUAction["💻 対策<br/>・プロセス最適化<br/>・不要プロセス停止<br/>・スケールアップ"]
IOWAIT --> IOAction["💾 対策<br/>・遅いクエリ最適化<br/>・ログ出力削減<br/>・高速ディスクへ変更"]
STEAL --> STAction["☁️ 対策<br/>・インスタンスタイプ変更<br/>・専用インスタンスへ移行<br/>・クラウド業者に問い合わせ"]
CPUAction --> End["✅ 解決"]
IOAction --> End
STAction --> End
style Start fill:#ffebee
style End fill:#e8f5e9
style CPU fill:#fff3e0
style IOWAIT fill:#fff3e0
style STEAL fill:#fff3e0
style CPUAction fill:#e3f2fd
style IOAction fill:#e3f2fd
style STAction fill:#e3f2fd
調査手順
# 1. まず全体像を把握
$ uptime
load average: 15.00, 10.00, 5.00 # 急上昇中
# 2. 何が原因か切り分け
$ top
# → %CPU, %wa, %st を確認
# 3a. CPU使用率が高い場合
$ ps aux --sort=-%cpu | head -5 # CPUを使っているプロセス特定
# 3b. I/O wait(wa)が高い場合
$ iostat -xz 1 # ディスクI/Oを確認
$ iotop -o # どのプロセスがI/Oを使っているか
# 3c. steal(st)が高い場合
# → VMホストが過負荷、クラウドならインスタンス変更を検討
シナリオ2: 「メモリ不足」
調査フロー
flowchart TB
Start["🧠 メモリ不足の疑い"] --> Step1["1️⃣ メモリ状況確認<br/><code style='color: white'>free -h</code><br/>available を見る"]
Step1 --> Step2["2️⃣ スワップ確認<br/><code style='color: white'>vmstat 1</code><br/>si/so が0以外なら危険"]
Step2 --> Check{スワップが<br/>使われている?}
Check -->|Yes| Critical["⚠️ 危険な状態<br/>スワップ使用中"]
Check -->|No| Step3["3️⃣ メモリ使用プロセス特定"]
Critical --> Step3
Step3 --> Process["<code style='color: white'>ps aux --sort=-%mem | head -10</code>"]
Process --> Step4["4️⃣ OOM Killer確認<br/><code style='color: white'>dmesg | grep -i 'out of memory'</code>"]
Step4 --> OOM{OOM Killerが<br/>発動した?}
OOM -->|Yes| OOMAction["💥 OOM発生<br/>・メモリ増設必須<br/>・プロセス削減<br/>・メモリリーク調査"]
OOM -->|No| Step5["5️⃣ プロセス別詳細<br/><code style='color: white'>cat /proc/[PID]/status</code>"]
Step5 --> Action["📊 対策<br/>・大量メモリ使用プロセス特定<br/>・プロセス最適化 or 停止<br/>・メモリ増設検討"]
OOMAction --> End["✅ 対策実施"]
Action --> End
style Start fill:#ffebee
style End fill:#e8f5e9
style Critical fill:#ffebee
style OOMAction fill:#ffebee
style Action fill:#e3f2fd
style Step1 fill:#e3f2fd
style Step2 fill:#e3f2fd
style Step3 fill:#e3f2fd
style Step4 fill:#e3f2fd
style Step5 fill:#e3f2fd
調査手順
# 1. メモリ状況確認
$ free -h
# → availableを見る
# 2. スワップが使われているか
$ vmstat 1
# → si/soが0以外なら危険
# 3. メモリを使っているプロセス特定
$ ps aux --sort=-%mem | head -10
# 4. OOM Killerが発動していないか
$ dmesg | grep -i "out of memory"
# 5. プロセス別の詳細メモリ使用量
$ cat /proc/1234/status | grep -E "(VmRSS|VmSwap)"
シナリオ3: 「ディスクが満杯」
調査フロー
flowchart TB
Start["💾 ディスクが満杯"] --> Step1["1️⃣ パーティション確認<br/><code style='color: white'>df -h</code>"]
Step1 --> Step2["2️⃣ 大きいディレクトリ探索<br/><code style='color: white'>du -h --max-depth=1 / | sort -hr</code>"]
Step2 --> Step3["3️⃣ 大きいファイル探索<br/><code style='color: white'>find / -type f -size +1G</code>"]
Step3 --> Step4["4️⃣ 削除済み but 開かれているファイル<br/><code style='color: white'>lsof | grep deleted</code>"]
Step4 --> Check{原因は?}
Check -->|"ログ肥大"| Log["📋 ログ問題<br/>・logrotate設定<br/>・古いログ削除<br/><code style='color: white'>ls -lh /var/log/</code>"]
Check -->|"Docker"| Docker["🐳 Docker問題<br/><code style='color: white'>docker system prune</code><br/>・未使用イメージ削除<br/>・コンテナクリーンアップ"]
Check -->|"一時ファイル"| Tmp["🗑️ 一時ファイル<br/><code style='color: white'>/tmp</code> クリーンアップ<br/><code style='color: white'>/var/tmp</code> クリーンアップ"]
Check -->|"コアダンプ"| Core["💥 コアダンプ<br/><code style='color: white'>/var/crash</code> 確認<br/>不要なdump削除"]
Log --> End["✅ 容量確保"]
Docker --> End
Tmp --> End
Core --> End
style Start fill:#ffebee
style End fill:#e8f5e9
style Log fill:#fff3e0
style Docker fill:#fff3e0
style Tmp fill:#fff3e0
style Core fill:#fff3e0
style Step1 fill:#e3f2fd
style Step2 fill:#e3f2fd
style Step3 fill:#e3f2fd
style Step4 fill:#e3f2fd
調査手順
# 1. どのパーティションが満杯か
$ df -h
# 2. 大きいディレクトリを探す
$ du -h --max-depth=1 / 2>/dev/null | sort -hr | head -20
# 3. 大きいファイルを探す
$ find / -type f -size +1G 2>/dev/null
# 4. 削除されたけど開かれているファイル
$ lsof | grep deleted
# 5. ログローテーションを確認
$ ls -lh /var/log/
よくある原因と対処
| 原因 | 対処 |
|---|---|
| ログファイル肥大 | logrotate設定、古いログ削除 |
| Dockerイメージ | docker system prune |
| 一時ファイル | /tmpのクリーンアップ |
| コアダンプ | /var/crashの確認 |
シナリオ4: 「接続できない」
調査フロー
flowchart TB
Start["🚫 接続できない"] --> Step1["1️⃣ サービス起動確認<br/><code style='color: white'>systemctl status nginx</code>"]
Step1 --> Q1{サービスは<br/>起動している?}
Q1 -->|No| StartService["サービス起動<br/><code style='color: white'>systemctl start nginx</code>"]
Q1 -->|Yes| Step2["2️⃣ ポートLISTEN確認<br/><code style='color: white'>ss -tlnp | grep :80</code>"]
StartService --> Step2
Step2 --> Q2{ポートが<br/>LISTEN?}
Q2 -->|No| Config["設定ミス<br/>・bind address確認<br/>・ポート番号確認<br/>・設定ファイル確認"]
Q2 -->|Yes| Step3["3️⃣ ファイアウォール確認<br/><code style='color: white'>iptables -L -n</code><br/><code style='color: white'>ufw status</code>"]
Step3 --> Q3{ファイアウォールが<br/>ブロック?}
Q3 -->|Yes| Firewall["ファイアウォール許可<br/><code style='color: white'>ufw allow 80</code><br/><code style='color: white'>iptables ...</code>"]
Q3 -->|No| Step4["4️⃣ 接続数上限確認<br/><code style='color: white'>ss -s</code>"]
Firewall --> Step4
Step4 --> Q4{接続数が<br/>上限?}
Q4 -->|Yes| ConnLimit["接続数制限<br/>・max connections 増加<br/>・接続タイムアウト設定<br/>・不要接続クローズ"]
Q4 -->|No| Step5["5️⃣ ログ確認<br/><code style='color: white'>journalctl -u nginx --since '10m ago'</code>"]
Step5 --> LogAction["ログから原因特定<br/>・エラーメッセージ確認<br/>・アクセスログ確認"]
Config --> End["✅ 接続可能"]
ConnLimit --> End
LogAction --> End
style Start fill:#ffebee
style End fill:#e8f5e9
style StartService fill:#e3f2fd
style Config fill:#fff3e0
style Firewall fill:#fff3e0
style ConnLimit fill:#fff3e0
style LogAction fill:#e3f2fd
調査手順
# 1. サービスが起動しているか
$ systemctl status nginx
# 2. ポートがLISTENしているか
$ ss -tlnp | grep :80
# 3. ファイアウォール
$ iptables -L -n
$ ufw status
# 4. 接続数が上限に達していないか
$ ss -s
# 5. ログにエラーがないか
$ journalctl -u nginx --since "10 minutes ago"
シナリオ5: 「特定のプロセスが暴走」
調査フロー
flowchart TB
Start["🔥 プロセスが暴走"] --> Step1["1️⃣ プロセス特定<br/><code style='color: white'>top</code> (Pキーでソート)<br/>または<br/><code style='color: white'>ps aux --sort=-%cpu</code>"]
Step1 --> Step2["2️⃣ プロセス詳細確認<br/><code style='color: white'>ps -p [PID] -o pid,ppid,user,%cpu,%mem,start,cmd</code>"]
Step2 --> Step3["3️⃣ 何をしているか調査<br/><code style='color: white'>strace -p [PID]</code>"]
Step3 --> Step4["4️⃣ 開いているファイル確認<br/><code style='color: white'>lsof -p [PID]</code>"]
Step4 --> Check{停止すべき?}
Check -->|"正常終了"| Kill["<code style='color: white'>kill [PID]</code><br/>SIGTERM(15)で正常終了"]
Check -->|"応答しない"| Kill9["<code style='color: white'>kill -9 [PID]</code><br/>SIGKILL(9)で強制終了"]
Check -->|"様子見"| Monitor["継続監視<br/><code style='color: white'>watch -n 1 'ps -p [PID] -o %cpu,%mem'</code>"]
Kill --> Verify["プロセス終了確認<br/><code style='color: white'>ps -p [PID]</code>"]
Kill9 --> Verify
Monitor --> Check
Verify --> End["✅ 対処完了"]
style Start fill:#ffebee
style End fill:#e8f5e9
style Kill fill:#fff3e0
style Kill9 fill:#ffebee
style Monitor fill:#e3f2fd
style Step1 fill:#e3f2fd
style Step2 fill:#e3f2fd
style Step3 fill:#e3f2fd
style Step4 fill:#e3f2fd
調査手順
# 1. プロセスの特定
$ top # Pキーで CPU順ソート
# 2. プロセスの詳細
$ ps -p 1234 -o pid,ppid,user,%cpu,%mem,start,cmd
# 3. 何をしているか
$ strace -p 1234
# 4. 開いているファイル
$ lsof -p 1234
# 5. 必要なら停止
$ kill 1234 # 正常終了
$ kill -9 1234 # 強制終了
Part 8: 監視のベストプラクティス
定常監視で見るべき項目
| カテゴリ | 指標 | 閾値(目安) |
|---|---|---|
| CPU | Load Average / コア数 | < 1.0 |
| CPU | I/O wait | < 10% |
| メモリ | Available | > 20% |
| メモリ | Swap使用量 | = 0 |
| ディスク | 使用率 | < 80% |
| ディスク | I/O await | < 20ms |
| ネットワーク | 接続数 | 上限の80%以下 |
| プロセス | ゾンビプロセス | = 0 |
ワンライナー集
全体状況の確認
# 1コマンドで全体像
$ echo "=== Load ===" && uptime && echo "=== Memory ===" && free -h && echo "=== Disk ===" && df -h && echo "=== Top Processes ===" && ps aux --sort=-%cpu | head -5
異常検知
# Load Averageが高いかチェック
$ [ $(awk '{print int($1)}' /proc/loadavg) -gt $(nproc) ] && echo "HIGH LOAD"
# ディスク使用率80%超えチェック
$ df -h | awk '$5 > 80 {print "WARNING:", $0}'
# スワップが使われているかチェック
$ [ $(free | awk '/Swap/{print $3}') -gt 0 ] && echo "SWAP IN USE"
監視コマンド選択フローチャート
flowchart TB
Start["🔍 何を調査する?"] --> Category{調査カテゴリ}
Category -->|"全体状況"| Overall["📊 全体状況<br/>━━━━━━<br/><code style='color: white'>uptime</code> - 負荷確認<br/><code style='color: white'>top / htop</code> - リアルタイム監視"]
Category -->|CPU| CPU["💻 CPU<br/>━━━━━━<br/>基本:<code style='color: white'>top</code> / <code style='color: white'>uptime</code><br/>詳細:<code style='color: white'>mpstat -P ALL 1</code><br/>統計:<code style='color: white'>vmstat 1</code>"]
Category -->|メモリ| MEM["🧠 メモリ<br/>━━━━━━<br/>基本:<code style='color: white'>free -h</code><br/>詳細:<code style='color: white'>cat /proc/meminfo</code><br/>スワップ:<code style='color: white'>vmstat 1</code> (si/so)"]
Category -->|ディスク| DISK["💾 ディスク<br/>━━━━━━<br/>容量:<code style='color: white'>df -h</code><br/>使用量:<code style='color: white'>du -sh /*</code><br/>I/O:<code style='color: white'>iostat -xz 1</code><br/>プロセス別:<code style='color: white'>iotop -o</code>"]
Category -->|ネットワーク| NET["🌐 ネットワーク<br/>━━━━━━<br/>接続状況:<code style='color: white'>ss -s</code><br/>ポート:<code style='color: white'>ss -tlnp</code><br/>帯域:<code style='color: white'>iftop / nethogs</code><br/>パケット:<code style='color: white'>tcpdump</code>"]
Category -->|プロセス| PROC["⚙️ プロセス<br/>━━━━━━<br/>一覧:<code style='color: white'>ps aux</code><br/>特定:<code style='color: white'>pgrep / pkill</code><br/>詳細:<code style='color: white'>lsof -p [PID]</code><br/>追跡:<code style='color: white'>strace -p [PID]</code>"]
Category -->|ログ| LOG["📋 ログ<br/>━━━━━━<br/>systemd:<code style='color: white'>journalctl -u [service]</code><br/>カーネル:<code style='color: white'>dmesg -T</code><br/>ファイル:<code style='color: white'>tail -f /var/log/...</code><br/>検索:<code style='color: white'>grep -i error</code>"]
Overall --> Next{さらに<br/>深掘り?}
CPU --> Next
MEM --> Next
DISK --> Next
NET --> Next
PROC --> Next
LOG --> Next
Next -->|Yes| Detailed["🔬 詳細調査<br/>・問題プロセス特定<br/>・ログ詳細確認<br/>・リソース履歴確認"]
Next -->|No| End["✅ 調査完了"]
Detailed --> End
style Start fill:#e3f2fd
style End fill:#e8f5e9
style Overall fill:#fff3e0
style CPU fill:#fff3e0
style MEM fill:#fff3e0
style DISK fill:#fff3e0
style NET fill:#fff3e0
style PROC fill:#fff3e0
style LOG fill:#fff3e0
style Detailed fill:#e3f2fd
まとめ
この記事で紹介したコマンドを、目的別にまとめます:
まず実行するコマンド
| 目的 | コマンド |
|---|---|
| 全体状況 | uptime, top, htop |
| メモリ | free -h |
| ディスク容量 | df -h |
| ディスクI/O | iostat -xz 1 |
| ネットワーク | ss -s |
| ログ | journalctl -p err --since "1 hour ago" |
深掘りするコマンド
| 目的 | コマンド |
|---|---|
| CPU詳細 | mpstat -P ALL 1, vmstat 1 |
| メモリ詳細 | /proc/meminfo, vmstat 1 |
| ディスク詳細 | iotop, lsof |
| ネットワーク詳細 | ss -t, tcpdump, nethogs |
| プロセス詳細 | ps auxf, strace -p PID, lsof -p PID |
参考資料
- Linux Performance - Brendan Gregg
- USE Method - リソース分析手法
- Linux Performance Analysis in 60 Seconds - Netflix Tech Blog
この記事が、サーバー運用の現場で役立てば幸いです。
「何を見ればいいか分からない」という状態から、「ここを見れば分かる」という状態になれることを目指しました。