クエリは回してみないと分からない
一言でいうと
PromQLは、間違えてもエラーを出さず、空の結果を出します。そのため、クエリが正しいかどうかは、本物のメトリクスの上で動かしてみて初めてわかります。
なぜ本物のPrometheusでなければならないのか
前のモジュールで、PromQLをいくつも書きました。ところが、それらのラボが動く場所にはPrometheus自体がなく、クエリが望む答えを返すか確認する方法がありませんでした。
PromQLは、文法が正しくても静かに空の結果を出すことが多くあります。エラーではなく空の結果なので、気づきにくいのです。
- 範囲セレクターが収集周期より短いと、
rate()が計算する点が足りません - ラベル名を1つ間違えると、マッチする時系列がありません
- レコーディングルールは登録されたあとから計算するので、過去の区間は空です
up == 0が捉えられないもの
最も価値のある落とし穴です。up == 0は、ターゲットがあるのに応答しないときだけ真になります。
Podが丸ごと消えると、サービスディスカバリからターゲットが外れて、upの時系列自体がなくなります。ないものは0ではないので、アラートがかかりません。
「全部死んだのに、アラートが1つも来なかった」は、ここから生まれます。
up == 0 대상이 있는데 응답이 없다
absent(up{job="x"}) 그 job 의 대상이 아예 없다
count(up{job="x"}) < 3 예상보다 적다 ← 실무에서 가장 쓸모 있다
設定が反映されない場所
ConfigMapボリュームは、kubeletが定期的に同期します(約60秒)。伝播する前にreloadを叩くと、古い設定をもう一度読み込みますが、reloadは200を返します。そのため、設定が間違っていると思い込んで、見当違いの場所を直すことになります。
そして、subPathでマウントすると、更新がまったく伝播されません。
アラートを役に立つものにするルール
アラートが多くなると、人が見なくなり、そうなると、ないのと同じになります。4つを守れば、ほとんどが取り除かれます。
原因ではなく、症状でかけます。「CPU 80%超過」は、人を起こす理由ではありません。「決済エラー率5%超過」は理由です。原因の指標はダッシュボードに置き、アラートは、ユーザーが経験することにだけかけます。
forを必ず付けます。瞬間的なスパイクで起こすと、信頼を失います。
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 10m # 10분 동안 계속 참일 때만
labels: {severity: page}
annotations:
summary: "5xx 비율 {{ $value | humanizePercentage }}"
runbook: "https://…/runbooks/high-error-rate"
runbookのリンクを付けます。午前3時に目を覚ました人が何を見るべきかが書かれていないアラートは、不安だけを生みます。
バーンレート(burn rate)でかけます。SLOが99.9%なら、1か月のエラーバジェットは43分です。「今の速度で進むと、バジェットをいつ使い切るか」でかければ、短くて激しいものと、長くて弱いものを、1つのルールで捉えられます。
빠른 소진: 1시간 창에서 예산의 2% 이상 → 즉시 호출
느린 소진: 6시간 창에서 예산의 5% 이상 → 티켓
指標のカーディナリティがPrometheusを殺す
ラベル値1つが、時系列1つです。user_idをラベルに入れると、ユーザー数だけ時系列ができ、メモリがその分だけ必要になります。
# 지금 무엇이 시계열을 많이 쓰나
topk(10, count by (__name__)({__name__=~".+"}))
# 특정 지표의 라벨별 카디널리티
count(count by (route) (http_request_duration_seconds_count))
Prometheusの/status/tsdb画面にも、上位の指標とラベルが表示されます。時系列が100万個を超えると、メモリが数GB単位で増え、再起動時のWALの再生が長くなって、数分間、指標が空に見えます。
値が無限に増えうるもの(リクエストID、メール、完全なURL)は、指標ではなく、ログやトレースに入れます。この区別がオブザーバビリティの設計の半分です。
実務で本当に大切なこと
アラートは、up == 0ではなくcount(...) < Nでかけます。消えたターゲットは0ではなく、ないものなので、up == 0は、最大の事故で沈黙します。期待する個数がわかっているjobごとに、個数のアラートを1つずつ置くことが、大きな価値を持ちます。
設定を直したあとは、reloadの200を信じず、反映された値を読み戻します。ConfigMapの伝播は最大60秒かかり、subPathマウントはまったく更新されません。/api/v1/status/configで、現在起動している設定を確認することが、唯一確実な方法です。
レコーディングルールは、登録された時点から計算します。ダッシュボードをルールベースに移すと、過去の区間が空に見えます。移行するときは、2つの式をしばらく並べて置き、重なる区間を照合する必要があります。
次のラボで、これらをすべて本物のPrometheusの上で自分で確認します。