はじめに
パフォーマンス問題の厄介さは、「毎回起きるとは限らない」ことです。障害対応の現場ではだいたいこうなります。
- たしかに遅かったが、今は治っている
- 監視は“CPU使用率”くらいで、原因に辿り着けない
- 次に再発したとき、同じ調査をゼロからやり直す
- 結果、場当たり的な最適化が積み重なって運用が重くなる
ここを抜けるコツは、観測を二段構えにすることです。
- 低負荷メトリクスを常時取り続ける(継続観測)
- 異常時だけ短時間プロファイルで深掘る(スポット観測)
この2つを“手順として”用意すると、再発時の対応が早くなり、改善も再現性が出ます。この記事では、CPU/メモリ/ネットワークを対象に、何を常時計測し、いつ・どうやって短時間プロファイルに切り替えるかを運用目線でまとめます。
座学
1) 継続観測で本当に欲しいのは「症状の再現」ではなく「状態の証拠」
観測の目的は「速くする」ではなく、まず “何が支配していたか”を確定できる証拠 を残すことです。
そして証拠は、重たい計測(プロファイル)よりも、軽い指標(メトリクス)のほうが“常に”残せます。
- 低負荷メトリクス:常に残す(90日保持など)
- プロファイル:異常時だけ残す(数分分・数回分だけ保存)
この設計にすると、普段の運用コストを増やさずに、トラブル時の解像度を上げられます。
2) 監視の指標は「インフラ・プロセス・アプリ」の3層で揃える
CPU/メモリ/ネットワークは、どの層が原因でも症状が似ます。だから最初から“3層セット”で揃えるのが安全です。
- インフラ層(ホスト/ノード)
CPU利用率、load、メモリ残量、ネットワーク帯域/ドロップ、ディスクI/O など
→ “ホスト全体が苦しいか”を判断 - プロセス層(Nodeプロセス)
CPU時間、RSS、open fd、スレッド数、コンテキストスイッチ、再起動回数 など
→ “このプロセスが犯人か”を判断 - アプリ層(HTTP/API/ジョブ)
レイテンシ(p95/p99)、エラー率、RPS、キュー長、イベントループ遅延、GC傾向 など
→ “ユーザー影響と直接つながる”指標
3) “いつ深掘るか”を先に決める(トリガー条件がないとプロファイルが腐る)
プロファイルは強いですが、常時ONにすると重い・容量食う・セキュリティ上の扱いも難しい。
なので、深掘りのトリガーを先に決めます。 例:
- p95レイテンシが基準の2倍を5分継続
- エラー率が1%超え
- イベントループ遅延 p95 が 50ms 超え
- RSSがベースラインから +30% して戻らない
- TCP再送が急増
- Pod/プロセスの再起動が増える
トリガーが決まると、短時間プロファイルは「迷ったらやる」ではなく「条件を満たしたらやる」になります。
4) 継続観測の設計でよくある失敗
- CPU使用率だけ見ている:CPUが低くても遅い(I/O待ちやネットワーク)
- 平均しか見ない:平均は正常でもp95/p99が崩れている
- 保持期間が短い:週次・月次の周期性が見えない
- アラートが多すぎる:誰も見なくなる
- “調査の手順”がない:メトリクスを眺めて終わる
設計のゴールは「数字を集める」ではなく、異常→切り分け→深掘り→改善→再発防止の流れを回せることです。
ハンズオン
ここでは、実装や製品を固定しすぎない形で、すぐ導入できる“骨格”を作ります。
やることは4つです。
- 常時メトリクス(低負荷)を揃える
- ダッシュボードの最小セットを作る
- アラート(深掘りトリガー)を決める
- 短時間プロファイルの運用手順(Runbook)を作る
1) 低負荷メトリクスの“最小セット”を決める
まずはこれだけ揃えると、CPU/メモリ/ネットワークの切り分けが一気に楽になります。
インフラ層(ホスト/ノード)
- CPU:使用率、load average
- メモリ:available、swap、OOM発生
- ネットワーク:送受信帯域、drop、error、TCP再送(取れるなら)
プロセス層(Nodeプロセス)
- CPU time(user/system)
- RSS(常駐メモリ)
- open file descriptors
- スレッド数 / context switches(取れるなら)
- 再起動回数、uptime
アプリ層(Nodeアプリ)
- RPS
- レイテンシ(p50/p95/p99)
- エラー率(4xx/5xx)
- イベントループ遅延(p95)
- GCの当たり(回数や時間を取れるなら)
コツ:まず“全体像が崩れた瞬間”が分かる程度で十分。
細かい内訳は短時間プロファイルで取りに行く。
2) Nodeアプリに「壊れにくい計測」を仕込む(例:イベントループ遅延+HTTP計測)
アプリに入れる計測は、軽く、落ちにくく、運用が簡単なものから。
- イベントループ遅延(p95)
- リクエスト時間(ヒストグラム)
- エラー数
- 可能ならメモリ使用量(RSS/heapUsed)
実装方法は色々ありますが、方針は同じです。
“1リクエスト1ログ”だけだと集計が大変なので、メトリクスとして集計できる形に寄せます。
(Prometheus形式、StatsD、OpenTelemetry metricsなど、どれでもOK)
3) ダッシュボードは「3画面」だけ作る
最初から立派なダッシュボードを作ると疲れます。最小は次の3つで十分です。
画面A:ユーザー影響
- p95/p99レイテンシ
- エラー率
- RPS
画面B:Nodeプロセス健康
- CPU time(rate)
- RSS(推移)
- イベントループ遅延 p95
- 再起動回数/uptime
画面C:ホスト/ネットワーク健康
- ノードCPU/メモリ
- ネットワーク帯域・drop/error
- (取れるなら)TCP再送
この3画面があれば、障害の入口で「アプリなのか、ホストなのか、ネットワークなのか」の当たりがつきます。
4) “深掘りトリガー”をアラートにする(例)
アラートは多いほど良いわけではありません。深掘りへ進むための合図に絞ります。
- p95レイテンシ:基準値の2倍が5分
- 5xxエラー率:1%超が5分
- イベントループ遅延 p95:50ms超が5分
- RSS:ベースライン+30%が15分継続
- 再起動:10分で2回以上
- ネットワーク:drop/error増加、再送増加(環境で取れるなら)
ベースラインは最初から完璧に決めなくてOK。
まずは“明らかに壊れてる”閾値から始めて、運用しながら詰めます。
5) 短時間プロファイルの運用手順(Runbook)を作る
ここがこの記事の本題です。
「どうやって取るか」を文章化しておくと、再発時に強いです。
5-1) 共通:プロファイル採取のルール
- 採取は 短時間(例:30〜120秒)
- 対象は 該当インスタンス/Podだけ
- 採取前に 時刻、インスタンスID、トリガー指標 を記録
- 出力ファイルの保存先、保持期間、アクセス権を決める
- 顧客データが含まれうる場合の扱い(共有範囲)を決める
5-2) CPUが疑わしいとき(オンCPU)
- 条件:イベントループ遅延が跳ねる/CPU timeが増える/p95が悪化
- 採取:
- NodeのCPUプロファイル(
--cpu-prof系)を短時間で - あるいはOS側で
perfを短時間
- NodeのCPUプロファイル(
- 目的:
- “どの関数/どのスタックがCPUを食っているか”を確定
5-3) メモリが疑わしいとき(リーク/GC)
- 条件:RSSが右肩上がり/再起動が増える/GCっぽい停止がある
- 採取:
- ヒープスナップショットを2回(前後比較)
- GCログは短時間だけONにする(常時は騒がしい)
- 目的:
- “何が増え続けているか(保持している参照元)”を特定
5-4) ネットワークが疑わしいとき(再送/遅延)
- 条件:外部API待ちが増える/TCP再送が増える/RTTが跳ねる
- 採取:
- 接続統計(RTT、再送)
- 必要ならeBPF/OSトレースを短時間
- 目的:
- “アプリが遅い”ではなく“ネットワークが遅い”の証拠を固める
6) 最後に:改善後の“回帰検知”までを運用に入れる
短時間プロファイルで犯人が分かって修正したら、終わりではありません。
- 改善PRに「どの指標がどれだけ改善したか」を添える
- 同じトリガーが再発したときに、同じ手順で採取できるか確認
- ベースラインを更新(新しい通常状態を定義)
- 重要なら、再発防止のアラート条件を微調整
ここまで含めて初めて「継続観測が運用として回る」状態になります。
まとめ
CPU/メモリ/ネットワークの継続観測は、全部を常時計測することではありません。
軽い指標を“測り続けて”、異常時だけ短時間で“深掘る”。この二段構えが、運用コストと調査精度のバランスを取る現実的な解です。
- 常時:ユーザー影響(p95/p99/エラー)+プロセス健康(CPU time/RSS/イベントループ遅延)+ホスト健康(CPU/メモリ/ネットワーク)
- 異常時:短時間プロファイル(CPU/heap/OSトレース)で犯人を確定
- そして:改善→回帰検知→Runbook更新で“次に強くなる”
この流れを整えると、「遅い・重い」が“調査の属人芸”から“再現性のある運用”に変わります。
コメントを残す