3-5. モニタリング - top / htop / vmstat / SLI/SLO / 監視ツール
所要時間: 40-50分(がっつりなら2セッション分) ゴール: 「サイト遅い」と言われた時に、どのレイヤを誰の責任で見るか判断できる。SLI/SLOの基礎で「壊れた」を定量化できる コミット内容: 調査フローと使ったコマンドを
~/learn/linux/day17にコミット
この章が終わるとできること
top/htopで CPU・メモリ・load average を読めるfree -hのavailableを見て本当のメモリ余裕を判断できるvmstat/iostatで CPU待ち・I/O待ち を切り分けられるss -tnlpで listen ポートとプロセスを瞬時に確認できる- SLI / SLO / SLA の違いを答えられる
- 「ゴールデンシグナル」4つ(Latency / Traffic / Errors / Saturation)を覚えている
Day 6 / Day 13 とのつながり
- Day 6 で習った
ps/top/lsofがここで 本格運用 モードに昇格 - Day 13 (ログ管理) で集めたログが、ここで メトリクス化 される
- Day 11 (systemd) の
journalctlと組み合わせて「異常検知 → 原因特定」が30分で終わる
これができると何が嬉しいか
- 「サイト遅い」の Twitter 通報を 顧客より早く 検知できる
- 障害発生時、
top→vmstat→iostat→ssで 5分以内に原因レイヤを特定 できる - Day 21(デプロイ)の最終形 ─「監視つきで本番品質」が見えてくる
大前提: 「動いている」だけのサーバーは何の価値もない
本番サーバーが「動いているかどうか」を見ていない運用は、本番運用とは呼びません。
「動いている」と「健全」の間には大きな差があります:
- HTTPステータス200を返してはいるが、レスポンスが10秒かかる
- メモリリークで毎時100MBずつメモリ使用量が増えている(今夜OOMで死ぬ)
- ディスクI/Oで詰まっていてアクセスログが書けず、リクエストが捨てられている
- 1秒に1リクエストしか来ていない(顧客が離脱している = 売上0)
これらは監視していないと気づけない。気づけた頃には Twitter で「サイト落ちてる」と言われていて、もう遅い。
このレッスンで身に着けるべきは2つ:
- 障害発生時の調査スキル: top / vmstat / iostat / ss を使い分け、原因をレイヤごとに切り分け
- 平時の監視設計: 何を計測し、どこに閾値を置き、誰に通知するか
両方をきちんと押さえると、「本番で詰まらない」レベルになります。
セッション①: コマンドで現状把握(25-30分)
0. 録画スタート
mkdir -p ~/log ~/learn/linux/day17
cd ~/learn/linux/day17
script ~/log/linux_day17.log1. 監視の階層構造
監視の3階層
階層 何を見るか ツール例 インフラ層 CPU/メモリ/ディスク/ネットワーク top, free, df, ss, Prometheus node_exporter アプリケーション層 レスポンスタイム、エラー率、スループット アプリログ、APM(Datadog APM, New Relic) ビジネス層 売上、新規登録数、離脱率、KPI BIツール、データウェアハウス エンジニアが見るべきは インフラ + アプリ。ビジネス層もアプリログから派生可能だが、データ分析部署が見ることも多い。
障害調査時の動き方:
- ビジネス層で異常検知(売上が落ちた、登録数ゼロ)
- アプリ層を見る(エラーレートが上がっている? レスポンスタイムが伸びている?)
- インフラ層を見る(CPU spike? メモリ枯渇? ディスク埋まり?)
逆方向(インフラの異常を先に検知して、アプリへの影響を予測)も大事。
2. top vs htop vs vmstat vs iostat の使い分け
ざっくり言うと
「サイト遅い」と言われた時に最初に打つツールは症状で変わる。
top/htop= 今この瞬間 のスナップショット(プロセス別の CPU / メモリ)vmstat= 時系列の流れ(CPU・メモリ・I/O・スワップを1画面で)iostat= ディスク I/O 専用(待機時間・IOPS・利用率)
まず素朴な疑問
「サーバー遅いです」と言われた時、何を打つ?
症状: 「サーバーが遅い」
↓
[top で見たら CPU 100%] → どのプロセスが食ってる? → top で犯人特定
[top では正常だが応答遅い] → I/O が詰まってる? → iostat
[時系列で悪化していく] → スワップ発生してる? → vmstat
[プロセス見たいけど ツリー欲しい] → htop
top: 今この瞬間のプロセスランキング
top
# 上部: 全体サマリ (load average, CPU, memory)
# 下部: プロセス一覧(CPU使用率順)イメージ: 「マラソンの今の順位表」。誰がトップを走っているか即わかる。
htop: top の見やすい版
htop
# F5 でツリー表示 / F9 で kill / マウス操作可イメージ: 「top のリッチ UI 版」。色付き・ツリー・操作しやすい。
vmstat: 時系列の流れを追う
vmstat 5 10 # 5秒ごと10回
# procs --memory-- --swap-- ---io--- --cpu--
# r b swpd free si so bi bo us sy id waイメージ: 「心拍計のグラフ」。瞬間値ではなく波形が見える。
5秒ごとに si/so(スワップ in/out)が出ていれば、メモリ不足が進行中。
iostat: ディスク I/O 専用
iostat -dx 5
# Device r/s w/s r_await w_await %util
# sda 12.5 45.2 1.2 3.5 25.3イメージ: 「ディスクの混雑メーター」。%util が 80% 超なら詰まり確定。
対比表
| top | htop | vmstat | iostat | |
|---|---|---|---|---|
| 見る粒度 | プロセス単位 | プロセス単位 | システム全体 | デバイス単位 |
| 時系列 | リアルタイム更新 | リアルタイム更新 | 秒間隔で時系列 | 秒間隔で時系列 |
| ディスク I/O | ざっくり | ざっくり | あり (bi/bo) | 詳細 |
| スワップ | 数値だけ | 数値だけ | 動き (si/so) | なし |
| UI | テキスト | リッチ・色付き | 表だけ | 表だけ |
| 標準搭載 | 全環境 | 別途インストール | 全環境 | sysstat パッケージ |
| 強み | プロセス特定 | 操作性 | 時間軸 | ディスク詳細 |
切り分けフロー(実務)
「サーバー遅い」と報告
↓
top でプロセス一覧を見る
├─ CPU 100% のプロセスあり → そのプロセスを調査
├─ CPU は低いけど遅い → vmstat 1
│ ├─ wa(I/O待ち)が高い → iostat -dx 1 でディスク特定
│ └─ si/so(スワップ)が動いてる → メモリ不足
└─ プロセス見にくい → htop でツリー表示
一番覚えやすい説明
- 誰が CPU 食ってる? → top / htop
- 時間軸でどう変わってる? → vmstat
- ディスクが遅い? → iostat
# top(標準搭載)
top
# 上部: 全体サマリ
# load average: 0.42, 0.58, 0.51 ← 1分/5分/15分平均
# Tasks: 234 total, 1 running, 233 sleeping
# %Cpu(s): 5.0 us, 2.0 sy, 0.0 ni, 92.0 id, 1.0 wa, ...
# 下部: プロセス一覧(CPU使用率順)
# 主要な操作
# q - 終了
# P - CPU使用率順
# M - メモリ使用率順
# c - フルコマンド表示
# k - kill(PIDを聞かれる)
# 1 - CPUコア別表示
# h - ヘルプ
# htop(よりリッチなUI)
brew install htop # Mac
# sudo apt install htop # Linux
htop
# F2 - 設定
# F5 - tree表示
# F9 - kill
# F10 - 終了
# / - 検索
# u - ユーザーで絞り込みload average の本当の意味(よくある誤解)
ざっくり言うと
load average: 0.42, 0.58, 0.51 というあの数字。「CPU 使用率(%)ではない」。「実行待ち + 実行中のプロセス数」の平均で、コア数と比べて初めて意味が出る。
まず普通の誤解
load average: 4.50
↓
「使用率 450% ?? 100% 超えてるけど?」と混乱
load average は CPU 使用率ではない。
正しいモデル: スーパーのレジ
[レジ] 1台 │ 並んでいる人(待機) + 今レジしている人(実行中) = load
│
load = 1.0 → ▒ (1人が今レジ中。並びなし)
load = 3.0 → ▒ ▒ ▒ (1人がレジ中、2人が並んでる)
load = 0.5 → 半分の時間しか動いてない(暇)
コア数と比較する
4コアCPU = レジ4台
load = 4.0 → ▒▒▒▒ (4台フル稼働、待ち列なし)= ちょうど
load = 8.0 → ▒▒▒▒ + 4人待機 = 過負荷
load = 2.0 → 4台中2台稼働 = 余裕
判定の目安
| load / コア数 | 状態 |
|---|---|
| < 0.7 | 余裕 |
| 0.7 〜 1.0 | 注意 |
| > 1.0 | 高負荷、調査開始 |
| > 2.0 | 危険、対処必須 |
3つの数字の意味
load average: 0.42, 0.58, 0.51
↑ ↑ ↑
1分 5分 15分
- 1分だけ高い → 一時的なスパイク
- 15分が高い → 構造的な問題
- 1分 < 15分 → 改善中
- 1分 > 15分 → 悪化中
Linuxは I/O 待ちもカウントすることに注意
CPU が暇でも、ディスク I/O 待ちプロセスが多いと load が上がる。「load 高い = CPU 高い」は嘘で、**「load 高い = システムどこかで詰まってる」**が正解。
イメージ
- load average = 「レジに並んでいる人の数の平均」
- コア数 = レジ台数
- load > コア数 = 行列ができている = 過負荷
一番覚えやすい説明
- load の数字単体は意味なし
- load ÷ コア数 がプレッシャー指標
- 1.0 を超えたら詰まり始め
nproc # Linux: コア数確認
sysctl -n hw.ncpu # Mac: コア数確認
topの各列の意味
列 意味 PID プロセスID USER 実行ユーザー PR / NI 優先度 / nice 値(後述) VIRT 仮想メモリ全体(スワップ含む、実使用ではない) RES 実メモリ使用量(これが本当のメモリ消費) SHR 共有メモリ S 状態(R=実行中, S=スリープ, D=I/O待ち, Z=ゾンビ, T=停止) %CPU CPU使用率(1コア100%、4コアなら最大400%) %MEM 物理メモリの割合 TIME+ 累積CPU時間 COMMAND コマンド名 見るべき値:
%CPUが常に高いプロセス、%MEMがじわじわ増えるプロセス(メモリリーク疑い)、S=Dが多数(I/O詰まり)
3. vmstat - 仮想メモリと全体状況
top が「今この瞬間」のスナップショットなら、vmstat は 「時系列の流れ」 を秒単位で追う道具です。「メモリ・CPU・I/O が今どう動いているか」を1画面で同時に見られます。
- 何のコマンドか:
vmstat 5 10のように間隔と回数を指定して、CPU・メモリ・スワップ・I/O を時系列で出力するツール - いつ使うか: 「だんだん遅くなる」現象の調査、スワップ発生(
si/soカラム)の有無確認、wa(I/O 待ち)が高いかの即判定 - 解決する具体的な問題: 「スパイクなのか継続なのか」「CPU 詰まりなのか I/O 詰まりなのか」を、
topより広い視野で切り分ける
# 5秒ごと、10回出力
vmstat 5 10
# 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 123456 12345 234567 0 0 50 100 500 1200 5 2 92 1 0vmstat の重要列
列 意味 注目ポイント r 実行待ちプロセス数 コア数を超えたら CPU bound b I/O待ちプロセス数 1以上が続くなら ディスク bottleneck swpd スワップ使用量 (KB) 0であってほしい free 空きメモリ (KB) 少なくても cache が多ければOK cache キャッシュ (KB) Linuxはキャッシュ多用、これは健全 si / so スワップ in / out 継続的に発生していたら危険(メモリ不足) bi / bo ブロックI/O in / out (blocks/s) ディスク負荷 us / sy / id / wa CPU: ユーザー/システム/アイドル/I/O待ち wa が高い = I/O bottleneck vmstat の使い所: top よりも時系列の傾向を見るのに向く。「今この瞬間」より「5秒ごとに何が起きているか」。
4. free / df / du - メモリとディスク
メモリとディスクは「枯渇したら即座にサービス停止」する2大リソースです。free / df / du の3点セットで、それぞれの状況を即座に把握できるようにします。
- 何のコマンドか:
freeはメモリ使用量、dfはファイルシステムごとの使用量、duはディレクトリごとの容量を見るコマンド - いつ使うか: 「メモリ足りない?」と疑った時、
No space left on deviceエラーが出た時、ログディレクトリが肥大化していないか確認する時 - 解決する具体的な問題: 「
freeカラムだけ見て枯渇判定する」誤解、「dfとduの値がズレる」謎を、availableカラムとlsof | grep deletedで解消する
# メモリ使用量
free -h
# total used free shared buff/cache available
# Mem: 7.7Gi 2.3Gi 1.2Gi 128Mi 4.2Gi 5.0Gi
# Swap: 2.0Gi 0B 2.0Gi
# ディスク使用量(マウントポイント別)
df -h
df -hT # ファイルシステムタイプも表示
df -i # inode 使用量
# ディレクトリの容量
du -sh /var/log
du -sh /var/log/* # 直下のディレクトリ別
du -h --max-depth=1 /var # 1階層だけ
# 巨大ファイル特定
find / -size +100M -type f 2>/dev/null | xargs ls -lh | sort -k5 -hr | head
freeの available を見よ古い
freeはfreeカラムを見て「メモリ足りてない!」と判断しがち。間違い。Linux は「未使用メモリは無駄」という思想で、空きメモリをファイルキャッシュに積極的に使う。
freeカラムが少なくても、buff/cacheが多ければ「いつでも解放できる状態」。本当に見るべき:
availableカラム(Linux 3.14+)。「キャッシュを解放すれば使えるメモリ」を計算済み。total = used + free + buff/cache available ≒ free + 解放可能なbuff/cacheメモリ枯渇の判定:
available< 数百MB orswap used> 0 が続く → 危険freeだけ少なくてavailableが多い → 健全
duとdfの値がずれる時df -h / # 95% du -sh /* # 合計しても 50% しか使ってない?原因:
- 削除されたが open されているファイル: プロセスがファイルを開いたまま
rmしても、ディスクは解放されない。プロセス終了まで持ち越し。lsof | grep deletedで確認- マウントポイントに別ファイルシステムが重なっている:
/mntに他をマウントしていて、duには見えるがdfには別カウント- inode 不足: サイズに余裕があってもinode(ファイル数の上限)が枯渇。
df -iで確認「ディスク埋まったけど何を消せばいいか分からない」事案でハマるポイント。
5. iostat - ディスクI/Oの詳細
CPU でもメモリでもないのにサーバーが遅い時、犯人はだいたい ディスク I/O です。iostat でデバイスごとの IOPS・スループット・待機時間を詳細に追えます。
- 何のコマンドか:
iostat -dxで各ブロックデバイスの読み書き回数・帯域・平均待機時間・利用率を表示するツール(sysstatパッケージ) - いつ使うか:
vmstatでwaが高かった時、DB の遅延が発生した時、ログ書き込みで詰まっている疑いがある時、SSD への換装効果を測定する時 - 解決する具体的な問題: 「ディスクが詰まっている」を
%utilとawaitで定量化し、アプリ側修正(ログ削減・トランザクション分割)か物理対処(SSD・IOPS増強)かの判断材料にする
# Mac は sysstat 入れる必要あり
# Linux: apt install sysstat
# 5秒間隔、10回
iostat -dx 5 10
# Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
# sda 12.5 45.2 500.3 1234.5 0.0 2.3 0.0 4.8 1.2 3.5 0.1 40.0 27.3 0.5 25.3iostat の主要列
列 意味 注目 r/s, w/s 秒間の読み書き回数 (IOPS) デバイスの性能限界が見える rkB/s, wkB/s 秒間スループット 帯域 bottleneck の指標 r_await, w_await 平均待機時間 (ms) 数十ms超 = 詰まっている %util デバイス使用率 80%以上が続くなら I/O bottleneck
%utilが高い時の対処:
- プロセスを特定:
iotop(Linux)、fs_usage(Mac)- アプリ側でI/O削減: ロギング頻度、トランザクションサイズ、N+1クエリ
- 物理的対処: SSDへ、I/O帯域の高いインスタンスへ
6. ss と netstat - ネットワーク接続
「ポート使われてる」「TIME-WAIT で詰まってる」「接続が増え続ける」── ネットワーク絡みのトラブルでまず叩くのが ss です。netstat の現代版で、桁違いに速いです。
- 何のコマンドか:
ss -tnlpで TCP リスニング状態とプロセス名を、ss -tanで TCP の全状態を表示するソケット統計コマンド - いつ使うか:
Address already in useエラーの犯人特定、TIME-WAIT が積み上がっていないかチェック、CLOSE-WAIT で接続リーク疑いの検出、外部APIへのコネクション数監視 - 解決する具体的な問題: 「リッスンしてるはずなのに繋がらない」「ポート枯渇」「謎のコネクションリーク」を、状態別の集計で即座に切り分ける
# 現代は ss 推奨(netstat より速い・情報豊富)
# リスニング中のTCPポート
ss -tnlp
# State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
# LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=2345,fd=5))
# UDP も含めて全部
ss -tunlp
# 確立済みTCP接続
ss -tnp
# 特定ポートに接続している相手
ss -tnp 'sport = :443'
# TIME_WAIT が大量にあるか
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c
# 5 ESTAB
# 2342 TIME-WAIT ← 大量にあると port exhaustion の懸念ss が netstat より優れている理由
- 速い:
/proc/net/*を直接読まず、カーネルから直接取得(数万接続でも瞬時)- 情報豊富: BBR/CUBIC 等のTCP輻輳制御アルゴリズム表示、
-oでタイマー- モダンな構文:
-t -u -n -l -pでTCP/UDP/数値/Listen/プロセスnetstat は2010年代以降メンテされていない。
net-toolsパッケージごと将来削除される予定。新規で覚えるのは ss だけでOK。
ESTAB vs TIME-WAIT vs CLOSE-WAIT
- ESTAB: 通常の接続中
- TIME-WAIT: 自分から close したが、最後のACKを取りこぼした可能性に備えて2MSL(〜60秒)待機。短命接続が多いと溜まる
- CLOSE-WAIT: 相手から close されたが、自分のアプリが close() を呼んでいない状態。バグの可能性(コネクションリーク)
TIME-WAIT が問題:
- 同じ送信元ポートが TIME-WAIT 中は再利用できない
- 短期接続を大量に張るアプリ(HTTPショート接続、外部API連打)で発生
- 解決: コネクションプール、HTTP keepalive、
net.ipv4.tcp_tw_reuseカーネルパラメータ
7. プロセス調査 - pidstat / lsof / strace
「犯人プロセスを特定したが、そいつが何をしているか分からない」── ここで使うのが pidstat / lsof / strace の3点セットです。プロセスを内部から覗き込めます。
- 何のコマンドか:
pidstatは特定プロセスのリソース消費、lsofは開いているファイル/ソケット、straceはシステムコール追跡 - いつ使うか: ポート占有プロセスの特定(
lsof -i :8080)、削除済みなのにディスク減らない原因調査(lsof | grep deleted)、ハング中プロセスの状態確認(strace -p) - 解決する具体的な問題: 「
topでプロセスが見つかっても、その先が分からない」を解消し、プロセス内部の挙動まで掘り下げて根本原因を特定する
# 特定プロセスのリソース使用量(毎秒)
pidstat -p <pid> 1
pidstat -d -p <pid> 1 # I/O のみ
# プロセスが開いているファイル/ソケット
lsof -p <pid>
lsof -i :8080 # 8080番ポートを使ってるプロセス
lsof | grep deleted # 削除済みファイルを掴んでいるプロセス(ディスク解放されない原因)
# プロセスのシステムコールを追跡(Linux)
sudo strace -p <pid> -c # 集計
sudo strace -p <pid> -e trace=network # ネットワーク系のみ
# Mac は dtruss
sudo dtruss -p <pid>
lsofの実務ユースケース
- 「ポート使われてる」エラー:
lsof -i :8080で犯人特定- 削除済みなのにディスク減らない:
lsof | grep deletedでプロセス特定 → 再起動か HUP シグナル- 特定ファイルを誰が開いている:
lsof /var/log/app.log起動時の
Address already in useを見て焦るが、lsof -i :ポートで即解決。
8. ログ集約 - journalctl
systemd 時代の Linux では、サービスごとに /var/log/ を探す代わりに journalctl 1コマンドで横断検索できます。「ログがどこにあるか問題」を一掃するツールです。
- 何のコマンドか:
journalctlは systemd-journald が一元管理するバイナリ形式ログを、サービス・時間・優先度でフィルタしながら閲覧するコマンド - いつ使うか: 「過去1時間の nginx エラー」を見たい時、サービスがクラッシュした時の直前ログ確認、複数サービスにまたがる障害の時系列追跡
- 解決する具体的な問題: 「ログファイルを探し回る」「
grepとawkを組み合わせて時間で絞る」手間を、--since・-u・-pの組み合わせで一発解決する
# systemd 系の統合ログ
journalctl # 全部
journalctl -u nginx # nginx サービスのみ
journalctl -u nginx -f # tail -f みたいに追従
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since today
journalctl -u nginx -p err # err以上の重要度のみ
journalctl --disk-usage # journal のサイズ確認
sudo journalctl --vacuum-time=7d # 7日より古いログを削除journal vs /var/log の rsyslog
昔の Linux はテキストログを
/var/log/配下に書き出していた。 systemd 登場後はjournalctl(バイナリ形式、構造化ログ)が並行運用される。どちらも参照可能だが、新しいディストリは journal がメイン:
/var/log/syslog,/var/log/messages: 伝統的なテキストログjournalctl: systemd 標準、検索・フィルタが強力本番運用: ローカルのログだけでは不十分。ログ集約基盤(Loki, Elasticsearch, CloudWatch Logs, Datadog Logs)に送って、複数サーバーから横断検索する。
セッション②: SLI/SLO と監視ツール(25-30分)
9. SLI / SLO / SLA - サービスの「健全さ」を定量化
コマンドで現状把握ができても、「壊れている」の定義が言葉だけだと、アラート設計も改善目標もブレます。それを数値で固定するのが SLI / SLO / SLA の枠組みです。
- 何のコマンドか: コマンドではなく概念フレームワーク。SLI(測定値)/ SLO(社内目標)/ SLA(顧客契約)の3階層で「サービスの健全さ」を定量化する
- いつ使うか: 監視ツール導入時に「何を測るか」を決める段階、アラート閾値を設計する時、運用チームと開発チームの会話の共通言語を作る時
- 解決する具体的な問題: 「サイト遅い」「たまにエラー」のような主観的な議論を消し、「p99 レイテンシ < 200ms を 99.9% 維持」のような共通指標に基づく意思決定に変える
SLI / SLO / SLA の違い
ざっくり言うと
「サービスの健全さ」を定量化する3階層。混同しがちだが、見ているレイヤがそれぞれ違う。
- SLI(Indicator)= 測ったデータそのもの(事実)
- SLO(Objective)= 社内の目標値(約束)
- SLA(Agreement)= 顧客との契約(罰則付き)
まず素朴な疑問
「サイトが落ちた」と言う時、どこから「落ちた」と判定する?
- HTTP 500 が 1 回出たら?
- 5 分間応答なしなら?
- 99.9% を下回ったら?
これを主観で議論しないようにする枠組みが SLI/SLO/SLA。
3階層の関係
[実際のシステム]
│ 測定
▼
[SLI] ← 観測した値(例: 過去30日の可用性 = 99.95%)
│ 目標と比較
▼
[SLO] ← 社内目標(例: 99.9% を維持)
│ 顧客と契約
▼
[SLA] ← 顧客契約(例: 99.5% を下回ったら返金)
数字で見る
| 階層 | 例 | 意味 |
|---|---|---|
| SLI | 「今月の p99 レイテンシは 180ms」 | 観測された事実 |
| SLO | 「p99 < 200ms を 99.9% の時間維持する」 | 社内目標 |
| SLA | 「p99 が 99.5% を下回ったら 10% 返金」 | 顧客契約 |
大事な順序: SLA < SLO < 実運用
99.5% ← SLA(顧客との契約、これを下回ると罰則)
↑
余裕
↓
99.9% ← SLO(社内目標、これを下回ったらアラート・改善)
↑
余裕
↓
99.99% ← 実際の運用(できればここを目指す)
顧客に約束する値より、社内の目標を厳しくしないと、契約違反が頻発する。
イメージ
- SLI = 「体温計の値」(37.8℃)
- SLO = 「健康基準」(37.5℃ 以下を保つ)
- SLA = 「保険契約」(38℃ を超えたら欠勤手当)
4つのゴールデンシグナル(SLI の代表例)
| 名前 | 意味 |
|---|---|
| レイテンシ | リクエストの所要時間(p50/p99) |
| トラフィック | req/sec |
| エラー率 | 5xx の比率 |
| 飽和度(Saturation) | リソース使用率(CPU/メモリ/接続プール) |
一番覚えやすい説明
- SLI = 測定結果(事実)
- SLO = 社内目標(自分との約束)
- SLA = 顧客契約(破ると罰金)
「SLA は SLO より緩く、SLO は実運用より緩い」が鉄則。
エラーバジェット
SLO を 99.9% とすると、許容できるエラー時間は月あたり:
- 100% - 99.9% = 0.1%
- 30日 × 24時間 × 60分 × 0.1% = 43分
この 43分が「エラーバジェット」。
- 月内にエラーバジェットを使い切ったら新機能リリース停止、安定化に集中
- バジェットに余裕があれば積極的にリリース・実験
SREの考え方: 「100%稼働は不可能、コストに対して非合理。99.9%で許容して、その範囲内で攻める」。
10. アラート設計の基本
SLO が決まったら、それを**「逸脱した時に誰かに知らせる」**仕組みがアラートです。設計を間違えると「アラート疲れ」で真の異常を見逃します。
- 何のコマンドか: 監視ツール(Prometheus Alertmanager / Datadog Monitor / CloudWatch Alarm)でアラート条件・通知先・重要度を宣言する設計手順
- いつ使うか: 監視導入時、夜間オンコール体制を整える時、過去のアラート疲労を見直してチューニングする時、新機能リリース時の重要メトリクス監視
- 解決する具体的な問題: 「アラートが多すぎて誰も見ない」「本当の障害を見逃す」を、ユーザー視点 SLO ベースの設計と症状ベースアラートで解消する
良いアラートの条件
Google SRE 本で挙げられている原則:
- 実用的: そのアラートを見てやるべきアクションが明確
- 緊急: 今すぐ対応すべき(朝まで待てるなら slack でOK)
- 根本原因ベース: 「ディスク90%」より「ユーザーがログインできない」
- 症状ベース: 「nginx の error.log が増えた」より「APIエラー率が3%超」
- 疲労を避ける: 誤検知が多いと無視されるようになる(アラート慣れ)
アンチパターン: 全部閾値アラート
CPU > 80% → アラート メモリ > 80% → アラート ディスク > 80% → アラート プロセス数 > 100 → アラート一見網羅的だが:
- 正常時もアラートが鳴る(バッチ実行中に CPU 100% は正常)
- 真の異常を見逃す: ユーザー影響と直結しない指標で疲労
- 対応不可能なアラート: 「CPU高い」と言われても、何を直せばいいか分からない
正解: ユーザー視点の指標(エラー率、レイテンシ、登録失敗率)を中心に。インフラ指標は補助。
アンチパターン: ログを見ずに再起動
「サーバー重いな、とりあえず再起動」
これをやると:
- 原因が永遠に分からない(再起動で症状が消えるから)
- 同じ問題が繰り返し起きる(メモリリーク、ファイルディスクリプタ枯渇、ゾンビプロセス)
- データ破損のリスク(不適切なshutdown)
正解: 再起動前にスナップショットを取る:
# メモリ・プロセス状態を記録 ps auxf > /tmp/before_restart_ps.log ss -tan > /tmp/before_restart_ss.log free -h > /tmp/before_restart_mem.log # アプリのスタックトレース(Go なら) kill -SIGQUIT <pid> # スタックトレースが stderr に出る
アンチパターン: 監視ダッシュボードを誰も見ない
高いお金を払って Datadog/New Relic を導入したのに、誰もダッシュボードを開いていない。
アラートだけ見て満足する運用は危険:
- アラート閾値より低いところで「ジワジワ悪化」しているのを見落とす
- 季節変動・週次パターンが見えない
- キャパシティプランニングの判断材料が無い
対策: 朝会で5分、ダッシュボードを全員で眺める文化を作る。「グラフを見る習慣」が監視文化の本質。
11. 監視ツール概要
実際に SLI を取って可視化するには監視ツールが必要です。世にあるツールは多いですが、選び方の軸を押さえれば迷いません。
- 何のコマンドか: コマンドではなくツール選定の指針。OSS(Prometheus + Grafana)vs SaaS(Datadog / New Relic)/ クラウド標準(CloudWatch)の3系統を、規模とコストで使い分ける
- いつ使うか: 新規プロジェクトの監視基盤を選ぶ時、既存の SaaS から OSS へ移行(または逆)を検討する時、k8s 上でのメトリクス基盤を選定する時
- 解決する具体的な問題: 「とりあえず Datadog」で破綻する課金、「自前 Prometheus」で人手不足、というツール選定ミスを、規模感とのマッチングで回避する
主要監視ツールの位置付け
ツール レイヤ 特徴 Prometheus + Grafana インフラ + アプリ OSS、Pull型、PromQL、k8s 標準 Datadog フル SaaS、APMからログまで統合、コスト高 New Relic フル SaaS、APM強い CloudWatch AWS リソース 標準で全部見れる、検索弱め Mackerel インフラ + アプリ 国産SaaS、Push型、はてな製 Zabbix インフラ OSS、古典、エンタープライズで多い Nagios インフラ 古典中の古典、現役ではほぼ Prometheus へ ELK / OpenSearch ログ 検索特化、ログ集約デファクト Loki ログ Prometheus エコシステム、軽量
Prometheus の基本(最も普及)
Pull型: Prometheus サーバーが各監視対象(exporter)に対して HTTPで
/metricsを取りに行く。構成:
[Node Exporter] ─┐ [Nginx Exporter] ┤ [Postgres Exp.] ├─→ [Prometheus] ─→ [Grafana] [カスタムアプリ] ─┘ └─→ [Alertmanager] → Slack/PagerDutyアプリ側でメトリクスを公開:
// Go の例 import "github.com/prometheus/client_golang/prometheus/promhttp" http.Handle("/metrics", promhttp.Handler())PromQL でクエリ:
# 過去5分のリクエストレート rate(http_requests_total[5m]) # エラー率(過去5分) sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
12. 実例: 「サイトが遅い」と報告された時の調査フロー
ユーザー: 「サイト遅いんだけど」
順を追って切り分け:
# ステップ1: 本当に遅いか確認(再現性)
curl -w "@curl-format.txt" -o /dev/null -s https://app.example.com/api/health
# DNS: 0.001s, Connect: 0.020s, TTFB: 2.500s, Total: 2.510s ← TTFB が遅い
# curl-format.txt の中身
cat > curl-format.txt <<'EOF'
time_namelookup: %{time_namelookup}s\n
time_connect: %{time_connect}s\n
time_appconnect: %{time_appconnect}s\n
time_pretransfer: %{time_pretransfer}s\n
time_redirect: %{time_redirect}s\n
time_starttransfer: %{time_starttransfer}s\n
----------\n
time_total: %{time_total}s\n
EOF
# ステップ2: 経路のどこか確認
# 2-1. クライアント側? (ブラウザDevToolsで)
# 2-2. CDN/DNS? (別経路から curl して比較)
# 2-3. Nginx?
# 2-4. アプリ?
# 2-5. DB?
# ステップ3: サーバー側を見る
ssh prod-web
# Nginx のアクセスログから upstream_response_time を見る
tail -1000 /var/log/nginx/access.log | jq '.upstream_response_time' | sort -n | tail
# → upstream が遅い = アプリが原因
# ステップ4: アプリのリソースを確認
top
# プロセスが100% CPUで張り付いている?
# → アプリの計算処理 or 無限ループ
# vmstat で全体感
vmstat 1 5
# wa が高い → I/O bottleneck
# si/so が動いている → メモリ不足でスワップ
# ステップ5: 詳しく追う
# 5-1. ロードが高い場合
ps auxf | head -20
# 5-2. I/O が遅い場合
iostat -dx 1 5
# 5-3. DBが疑わしい場合
# サイズの大きいクエリ、スロークエリログを確認
# PostgreSQL なら: SELECT * FROM pg_stat_activity WHERE state = 'active';
# 5-4. 外部APIが遅いか
ss -tn '( dport = :443 or dport = :80 )' | head
# ステップ6: 修正 or 一時対応
# 緊急なら: アプリ再起動(ただしスナップショット取ってから)
# 根本対応: コードレビュー、クエリ最適化、リソース増強「遅い」のレイヤ別チェックリスト
レイヤ 観点 コマンド/ツール DNS 名前解決遅延 dig,nslookupTCP接続 RTT ping,mtr,tracerouteTLS 証明書、ハンドシェイク openssl s_client -connectCDN ヒット率 CDNダッシュボード、 curl -IでヘッダLB / Nginx キュー、upstream時間 access.logアプリ エラー、計算、外部API APM、ログ DB クエリ時間、ロック、接続数 pg_stat_activity、スロークエリログキャッシュ ヒット率、エビクション Redis INFO ディスクI/O iostat iostat -dxネットワーク パケロス、輻輳 ss,tcpdump
13. 監視を構築する最小構成(学習用)
# Mac上で Prometheus + Grafana を Docker で起動
# (docker compose = 複数コンテナを1つの YAML で定義して同時起動するツール。
# Docker / docker compose の詳細は「インフラ」章で扱う。
# ここでは「3つのサービス(Prometheus, Grafana, node_exporter)を 1 コマンドで一括起動する道具」
# とだけ理解すればOK。動かなくても監視の概念は後段の説明で押さえられる)
mkdir -p ~/learn/linux/day17/monitoring
cd ~/learn/linux/day17/monitoring
cat > docker-compose.yml <<'EOF'
version: '3'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
node_exporter:
image: prom/node-exporter:latest
ports:
- "9100:9100"
volumes:
grafana-data:
EOF
cat > prometheus.yml <<'EOF'
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['node_exporter:9100']
EOF
docker compose up -d
# Prometheus UI: http://localhost:9090
# Grafana UI: http://localhost:3000 (admin/admin)
# Grafana で Prometheus データソース (http://prometheus:9090) を追加 → Node Exporter ダッシュボード ID 1860 をインポート練習課題
# 1. 「重い」プロセスを意図的に作って、top で見つける
# 別ターミナルで実行
yes > /dev/null &
PID=$!
# このターミナルで観察
top -p $PID
# kill する
kill $PID
# 2. メモリ食いプロセスを作る
# (python3 -c "..." は引数の文字列を Python ソースとして実行する形式。
# ここでは 500MB の空白文字列を作って input() で入力待ちさせ、メモリ使用を観察する用途。
# Python が無ければ代わりに `tail -f /dev/zero` などでも CPU/メモリの動きが見える)
python3 -c "x = ' ' * (500 * 1024 * 1024); input()" & # 500MB確保
free -h
ps aux | sort -k4 -rn | head
# 3. ディスク使用量を調査
df -h
du -sh ~/* | sort -h | tail
# 4. ネットワーク接続を見る
ss -tnlp
# 5. nginx を起動(前回の設定使う)→ ベンチマーク → ログから upstream_response_time を集計
nginx -c /full/path/to/nginx_local.conf
ab -n 1000 -c 10 http://localhost:8090/ # apache benchmark
# tail access.log で結果確認締め: git で証跡を残す
exit
cd ~/learn/linux/day17
git init
git add monitoring/
git commit -m "feat(linux): モニタリング基礎・Prometheus+Grafana のローカル構成"チェックリスト
- load average の正しい意味とコア数との関係を説明できる
-
topで CPU/メモリ 順にソートできる -
free -hでavailableを見る癖がついた -
dfとduの値がずれる理由を3つ挙げられる -
ss -tnlpで listen ポートとプロセスを確認できる - vmstat の si/so が継続的に出ている時の意味を説明できる
- SLI/SLO/SLA の違いを即答できる
- 「ゴールデンシグナル」4つを挙げられる
- 「サイト遅い」と言われた時の調査ステップを5つ以上書ける
詰まった時のチートシート
| やりたいこと | コマンド |
|---|---|
| CPU/メモリ 俯瞰 | top / htop |
| メモリ確認 | free -h |
| ディスク使用量 | df -h |
| 大容量ディレクトリ | du -sh /* | sort -h | tail |
| 巨大ファイル探索 | find / -size +100M -type f 2>/dev/null |
| ディスクI/O | iostat -dx 1 5 |
| ネットワーク接続 | ss -tnlp |
| プロセスのファイル | lsof -p <pid> |
| ポート使用プロセス | lsof -i :8080 |
| 削除済みファイル参照 | lsof | grep deleted |
| systemd ログ | journalctl -u <service> -f |
| プロセス強制終了 | kill -9 <pid> |
| プロセスにstacktrace要求(Go) | kill -SIGQUIT <pid> |
| 並列プロセス殺害 | pkill -f <pattern> |
| ベンチマーク | ab -n 1000 -c 10 <url> / wrk |
「実務OK」基準
- 「サイトが遅い」と聞いた時に、どのレイヤを見るか即決できる
topの数字(load, %CPU, %MEM, S列)を読めるfreeの available を見て本当のメモリ余裕を判断できるssでリッスン中サービスを瞬時に把握できる- SLI/SLO の設計を1サービス分書ける: 何を測り、目標値はいくつか
- アラート設計の良い/悪いを判断できる: ユーザー視点 vs インフラ視点
- 再起動前にスナップショットを取る癖がある
さらに深掘るなら
- 書籍: 『入門 監視』(オライリー) - 監視の哲学を学ぶ必読書
- 書籍: 『SRE サイトリライアビリティエンジニアリング』(オライリー) - Google SRE の原典、SLO設計の本家
- 書籍: 『Linuxカーネルの仕組み』(技術評論社) - top の各指標がカーネル内部でどう生成されるか
- 公式: https://prometheus.io/docs/ - Prometheus とPromQLの本家
- 公式: https://grafana.com/docs/ - Grafana
- Brendan Gregg のブログ: https://www.brendangregg.com/ - Linuxパフォーマンスの神
アンチパターン / 初心者やらかし事例
NG 1: load average を CPU 使用率と混同
load average: 4.0, 4.5, 3.8 # 「CPU 400%だ!」と慌てる
→ 4 コアなら load 4.0 は 「ちょうどフル」、8 コアなら半分。nproc でコア数を確認した上で判断。
NG 2: free の used だけ見て「メモリ満杯」と判断
total used free shared buff/cache available
Mem: 16Gi 14Gi 300Mi 100Mi 1.5Gi 1.8Gi
→ Linux はキャッシュにメモリを積極使用する。available が本当の余裕。
NG 3: df は満杯なのに du の合計が合わない
→ 削除されたが プロセスが掴んでいるファイル がスペースを占有している。
→ 対策: lsof | grep deleted で犯人特定 → プロセス再起動。
NG 4: メトリクスのアラートを「インフラ視点」だけで作る
CPU > 80% → アラート # 顧客は遅さを感じてないのに夜中に呼び出される
→ 対策: ユーザー視点(Latency / Error Rate) を主軸に SLO を引き、SLI で計測。CPU/Memory はその下の調査用。
自己評価チェックリスト
-
load averageをnprocの値と比較する習慣がついた -
free -hでavailableを見るクセが付いた -
ss -tnlpで listen ポートを瞬時に確認できる - SLI / SLO / SLA の3用語を区別できる
- 「ゴールデンシグナル」4つを言える
- 「サイト遅い」と聞いて、調査ステップを5個以上即答できる
次のレッスン: Day 20 (Final) - デプロイ
最終章は デプロイ ─ Level 1〜Level 3 の全部を統合する総合プロジェクト。
rsync / SSH script / GitHub Actions / systemd、ブルー/グリーン、ローリング、graceful shutdown、ロールバック、DB マイグレーション、シークレット管理まで。今日身につけた監視と組み合わせて、「本物のデプロイパイプライン」を組む。
→ Day 20: デプロイ へ