障害は突然起きるように見えて、多くの場合は予兆があります。
大がかりな監視基盤が無くても、見る数値を決めておけばかなり拾えます。
まず見るべき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を入れると調査時間が桁で変わる