データ・分析

障害の予兆をログとメトリクスから見つける — 個人〜小規模チームの現実的な監視

障害は突然起きるように見えて、多くの場合は予兆があります
大がかりな監視基盤が無くても、見る数値を決めておけばかなり拾えます。

まず見るべき4つ

1. エラー率(500系 / 全リクエスト)

絶対数ではなくで見ます。アクセスが増えればエラーの絶対数も増えるためです。

awk '{print $9}' access.log | sort | uniq -c

2. 応答時間の p95

平均は役に立ちません。悪化は p95 に先に出ます。

3. ディスク使用率

地味ですが、実際に最も多い停止原因です。
ログとバックアップで静かに埋まります。

df -h | awk '$5+0 > 80 {print}'

4. プロセスの再起動回数

systemctl show myapp -p NRestarts

自動復旧が効いていると障害に見えませんが、
再起動が増えている=何かが壊れかけているサインです。

アラートは鳴らしすぎない

監視で失敗する最大の原因は、アラートが多すぎて誰も見なくなることです。

  • 鳴らす:ユーザーが影響を受けている、または数時間以内に受ける
  • 鳴らさない:気になるが今日中に見れば十分(日次サマリで十分)
即時通知  : サイトが応答しない / エラー率が5%超 / ディスク90%超
日次まとめ: 応答時間の推移 / 4xx の傾向 / 再起動回数

この2段構成にしてから、通知を実際に読むようになりました

しきい値は実測から決める

「エラー率5%」のような数字を最初から決めても外します。
まず2週間記録し、平常時の分布を見てから決めます。

# 平常時の p95 が 0.8 秒 → しきい値は 2 倍の 1.6 秒に
threshold = normal_p95 * 2

ログに相関IDを入れる

障害調査で最も時間を食うのが「どのログが同じリクエストか分からない」ことです。

class RequestIDMiddleware:
    def __call__(self, request):
        request.id = uuid.uuid4().hex[:12]
        with logging_context(request_id=request.id):
            return self.get_response(request)

エラー画面にもこのIDを出しておくと、
ユーザーからの問い合わせとログが1発で突き合わせられます

エラーが発生しました(参照番号: a3f9c21b4e77)

まとめ

  • 見るのは「エラー率・p95・ディスク・再起動回数」の4つ
  • 即時通知は「ユーザーに影響がある」ものだけ。残りは日次まとめ
  • しきい値は平常時を2週間測ってから決める
  • 相関IDを入れると調査時間が桁で変わる