一晩で 70 件鳴ったのに利用者には何も起きていなかった
目標
原因基準のアラート4つと、症状基準のアラート1つを、実際のデータの上で数えてみて、ページ数と空振りのページの時間を根拠に、何を人に送り何を下げるかを決めます。
なぜ重要なのか
アラートを増やすのは簡単で、減らすのは難しいものです。難しい理由は、根拠がないからです。「このアラート、うるさくない?」は意見ですが、「このアラートは12時間に65回鳴り、そのうち230分は、ユーザーが何も体験しなかった時間だった」はデータです。データがあれば、会議が短くなります。そして同じデータが、継続時間のノブの値も決めてくれます。アラート設計はしきい値を選ぶ作業ではなく、人が引き受けられるページの総量の中で、何を検知するかを選ぶ作業です。
ステップ
/root/obs-alert-symptom/rules/causes.ymlにPrometheusのルールファイルを書いてください。グループ名はcausesで、アラートが4つ入ります。CauseQueueDepthはqueue_depth{job="shop-api",queue="orders"}が100を超えたとき、CauseDiskPredictはnode_filesystem_avail_bytes{job="node"}の直近1時間の傾向から6時間後を予測したときに0未満になるとき、CauseLatencyTailは直近5分基準のp99レイテンシが0.5秒を超えたとき、CauseTrafficLowは直近5分基準の1秒あたりのリクエスト数が55未満のときに鳴ります。promtool check rulesで検査が通る必要があります。このステップでは、for:を付けません。/root/obs-alert-symptom/count.pyを作成してください。python3 count.py '<경보 식>' <for 분>で呼び出すと(プレースホルダーはアラート式とforの分数です)、直近12時間を1分間隔で走査して、episodes=<호출 수> minutes=<울린 분>を1行出力します(プレースホルダーはページ数と鳴った分数です)。条件が真の分が連続してL分続いたとき、Lがfor + 1以上ならページ1回として数え、鳴った時間はL - for分です。forを渡さなければ0と見なします。/root/obs-alert-symptom/counts.tsvを作成してください。ヘッダーなしで4行、各行はタブで区切った3列<경보이름> <호출 수> <울린 분>です(プレースホルダーはアラート名、ページ数、鳴った分数です)。forは0のままにし、ステップ1のルールファイルに書いた4つのアラートを、名前のまま書きます。値は、ステップ2のツールで求めます。- ステップ3で最も多く鳴ったアラートを1つ選び、
forを0・5・15分に変えながら数え直してください。/root/obs-alert-symptom/for-effect.tsvにヘッダーなしで3行、各行は<for 분> <호출 수> <울린 분>です(プレースホルダーはforの分数、ページ数、鳴った分数です)。 /root/obs-alert-symptom/rules/symptom.ymlに、symptomグループとアラートSymptomErrorRatioを1つ書いてください。条件は直近5分基準の5xx応答率が1%を超えることで、for: 5mとrunbook_urlアノテーションを付けます。promtool check rulesを通したあと、同じ式をfor0で数えて、/root/obs-alert-symptom/symptom.txtにepisodes=<수> minutes=<분>を1行書いてください(プレースホルダーは数と分数です)。/root/obs-alert-symptom/overlap.pyを作成してください。python3 overlap.py '<원인 식>' '<증상 식>'で呼び出すと(プレースホルダーは原因の式と症状の式です)、直近12時間を1分間隔で走査して、cause_minutes=<원인이 참인 분> outside_minutes=<그중 증상이 참이 아닌 분>を1行出力します(プレースホルダーは原因が真の分と、そのうち症状が真でない分です)。そのツールで原因のアラート4つをそれぞれ測り、/root/obs-alert-symptom/falsepages.tsvに、タブで区切った3列<경보이름> <원인 분> <증상 밖 분>を4行書いてください(プレースホルダーはアラート名、原因の分、症状の外の分です)。/root/obs-alert-symptom/triage.tsvに5行を書いてください。各行はタブで区切った3列<경보이름> <page|ticket|dashboard> <근거>で(プレースホルダーはアラート名、page・ticket・dashboardのいずれか、根拠です)、原因のアラート4つとSymptomErrorRatioをすべて書きます。ルールは2つです。症状のアラートは必ずpageにすること、そしてステップ6で症状の外の分が60分を超えた原因のアラートは、pageにできないことです。根拠には、前のステップで得た数字が1つ以上入っている必要があり、20文字以上でなければなりません。/root/obs-alert-symptom/rules/page.ymlに、ステップ7でpageに分類したアラートだけを入れてください。グループ名はpageで、各アラートにはfor:が5分以上、labelsのseverity: page、annotationsのrunbook_urlが必要です。promtool check rulesを通したあと、それらのアラートをそれぞれのforの値で数えて、ページ数をすべて足した値を、/root/obs-alert-symptom/after.txtにpages_after=<수>として1行で書いてください(プレースホルダーは数です)。
参考
- 作業ディレクトリは
/root/obs-alert-symptomです。ルールファイルは/root/obs-alert-symptom/rules/の下に置いてください。/etc/prometheus/rules/に置くと、このPodのPrometheusが実際に評価を始めます。 - ルールの検査:
promtool check rules <파일>(プレースホルダーはファイル名です)。クエリの確認:promq "<PromQL>"。 - 区間データ:
/api/v1/query_rangeにquery・start・end・stepを渡します。条件が偽の時刻には、サンプルがそもそもありません。 - よくある間違い: 条件が真のサンプル数を、そのままページ数として数えること。連続した区間1つが、ページ1回です。
- よくある間違い:
forを付けると検知がその分遅れるという事実を省いて、ページ数だけを自慢してしまうこと。 - Monitoring Distributed Systems (SRE Book第6章)・Alerting on SLOs (SRE Workbook)・Being On-Call (SRE Book第11章)・Alerting rules・HTTP API — range queries
原因基準のアラート4つをルールファイルに書く
/root/obs-alert-symptom/rules/causes.ymlにPrometheusのルールファイルを書いてください。グループ名はcausesで、アラートが4つ入ります。CauseQueueDepthはqueue_depth{job="shop-api",queue="orders"}が100を超えたとき、CauseDiskPredictはnode_filesystem_avail_bytes{job="node"}の直近1時間の傾向から6時間後を予測したときに0未満になるとき、CauseLatencyTailは直近5分基準のp99レイテンシが0.5秒を超えたとき、CauseTrafficLowは直近5分基準の1秒あたりのリクエスト数が55未満のときに鳴ります。promtool check rulesで検査が通る必要があります。このステップでは、for:を付けません。
ルールファイルの骨組みは、groups: → - name: → rules: → - alert:とexpr:です。予測は、predict_linearに区間ベクトルと秒単位の先の時間を渡します。p99は、histogram_quantileにleごとに合算したrateを渡します。検査はpromtool check rules /root/obs-alert-symptom/rules/causes.ymlです。
何回鳴ったかを数えるツールを作る
/root/obs-alert-symptom/count.pyを作成してください。python3 count.py '<경보 식>' <for 분>で呼び出すと(プレースホルダーはアラート式とforの分数です)、直近12時間を1分間隔で走査して、episodes=<호출 수> minutes=<울린 분>を1行出力します(プレースホルダーはページ数と鳴った分数です)。条件が真の分が連続してL分続いたとき、Lがfor + 1以上ならページ1回として数え、鳴った時間はL - for分です。forを渡さなければ0と見なします。
/api/v1/query_rangeにstart・end・stepを渡すと、区間データが返ってきます。条件が偽の分にはサンプル自体がないので、応答に入っているタイムスタンプの集合を作り、1分の格子の上で連続した区間を数えればよいのです。Pythonの標準ライブラリだけを使います(urllib.request、json、time)。
原因アラート4つは、12時間に何回鳴ったか
/root/obs-alert-symptom/counts.tsvを作成してください。ヘッダーなしで4行、各行はタブで区切った3列<경보이름> <호출 수> <울린 분>です(プレースホルダーはアラート名、ページ数、鳴った分数です)。forは0のままにし、ステップ1のルールファイルに書いた4つのアラートを、名前のまま書きます。値は、ステップ2のツールで求めます。
ルールファイルから式を取り出してツールに渡せば、手で書き写すミスを減らせます。4つの数字がどれだけ開くかが、このステップの核心です。1つは、60回以上鳴ります。
継続時間1つで、ページがどれだけ減るか
ステップ3で最も多く鳴ったアラートを1つ選び、forを0・5・15分に変えながら数え直してください。/root/obs-alert-symptom/for-effect.tsvにヘッダーなしで3行、各行は<for 분> <호출 수> <울린 분>です(プレースホルダーはforの分数、ページ数、鳴った分数です)。
条件式はそのままにして、2つ目の引数だけを変えます。ページ数が減る代わりに何を失うかも、一緒に見てください。鳴った分が減るということは、検知がその分遅れるという意味です。
症状基準のアラートを1つ書く
/root/obs-alert-symptom/rules/symptom.ymlに、symptomグループとアラートSymptomErrorRatioを1つ書いてください。条件は直近5分基準の5xx応答率が1%を超えることで、for: 5mとrunbook_urlアノテーションを付けます。promtool check rulesを通したあと、同じ式をfor0で数えて、/root/obs-alert-symptom/symptom.txtにepisodes=<수> minutes=<분>を1行書いてください(プレースホルダーは数と分数です)。
比率は、5xxのrateの合計を全体のrateの合計で割ります。このアラートが、原因のアラートよりもずっと少なくしか鳴らないことが要点です。runbook_urlはannotationsの下に置きます。
ユーザーが何も体験しなかった時間に、何分鳴ったか
/root/obs-alert-symptom/overlap.pyを作成してください。python3 overlap.py '<원인 식>' '<증상 식>'で呼び出すと(プレースホルダーは原因の式と症状の式です)、直近12時間を1分間隔で走査して、cause_minutes=<원인이 참인 분> outside_minutes=<그중 증상이 참이 아닌 분>を1行出力します(プレースホルダーは原因が真の分と、そのうち症状が真でない分です)。そのツールで原因のアラート4つをそれぞれ測り、/root/obs-alert-symptom/falsepages.tsvに、タブで区切った3列<경보이름> <원인 분> <증상 밖 분>を4行書いてください(プレースホルダーはアラート名、原因の分、症状の外の分です)。
2つの式の「真の分の集合」をそれぞれ作り、差集合を数えればよいのです。ステップ2のツールの半分を関数として切り出せば、そのまま使えます。症状の外の分が大きいほど、「ユーザーは無事なのに、人だけを起こした」時間が長いという意味です。
数字を根拠に、ページ・チケット・ダッシュボードに分ける
/root/obs-alert-symptom/triage.tsvに5行を書いてください。各行はタブで区切った3列<경보이름> <page|ticket|dashboard> <근거>で(プレースホルダーはアラート名、page・ticket・dashboardのいずれか、根拠です)、原因のアラート4つとSymptomErrorRatioをすべて書きます。ルールは2つです。症状のアラートは必ずpageにすること、そしてステップ6で症状の外の分が60分を超えた原因のアラートは、pageにできないことです。根拠には、前のステップで得た数字が1つ以上入っている必要があり、20文字以上でなければなりません。
症状の外の分が0に近い原因のアラートは、症状とほぼ同じ時間にだけ鳴るという意味なので、ページとして残して調査の時間を節約できます。反対に、半分近くが真のアラートは、ページにしておくとフィルターを作らせてしまいます。
ページ用のルールファイルだけを残す
/root/obs-alert-symptom/rules/page.ymlに、ステップ7でpageに分類したアラートだけを入れてください。グループ名はpageで、各アラートにはfor:が5分以上、labelsのseverity: page、annotationsのrunbook_urlが必要です。promtool check rulesを通したあと、それらのアラートをそれぞれのforの値で数えて、ページ数をすべて足した値を、/root/obs-alert-symptom/after.txtにpages_after=<수>として1行で書いてください(プレースホルダーは数です)。
ルールファイルからalert名・expr・forを読んでステップ2のツールに渡せば、手で足す必要がありません。forの値は5mのような文字列なので、分単位の数字に変える必要があります。ステップ3のページ数の合計と比べてみてください。