SLOの決め方:SLI・エラーバジェット・バーンレートでアラートを設計する
CPUの閾値だけでは利用者への影響を判断しにくい。注文APIを例に、SLIの分母と計測地点、99.9%の予算、複数の窓で見るバーンレート、メトリクスからトレースへ進む調査手順を解説します。
SLI・SLO・SLAの違いと、最初に決めること
| 用語 | 意味 | 注文APIでの例 |
|---|---|---|
| SLI | 利用者に提供したサービス品質の測定値 | 対象リクエストのうち2秒以内に正しく成功した割合 |
| SLO | SLIに対する目標と評価期間 | 直近30日で99.9%以上 |
| SLA | 合意したサービス水準と未達時の取り扱い | 契約に定めた対象、条件、対応 |
ここでは架空の注文APIを使います。2秒・99.9%は推奨値ではありません。利用者が待てる時間、注文の重要度、依存先と運用の費用を確認し、実測した現状と比較して目標を決めます。異なる操作の全体平均だけで、高価値な注文経路の失敗を隠さないようにします。
SLIの分母と計測地点を先に固定する
「成功数÷全件数」だけでは曖昧です。この例では正規の注文作成リクエストを対象とし、正しい注文結果を2秒以内に返したものをgood、それ以外をbadとします。タイムアウトや、サービス都合の過負荷拒否もbadへ数えます。入力不正や利用者のキャンセルをどう扱うかは事前に決め、障害後に都合よく分母から外しません。
- 入口:対象の操作と利用者、計測を始める時点を決める。リトライ1回を別リクエストとして数えるか、業務操作単位で数えるかも固定する。
- 出口:HTTPの2xxだけでなく、成功の業務条件と時間制限を決める。非同期の受付なら、受付品質と後続の完了期限を別に測る。
- 欠落:アプリへ届かない失敗や、終了しない処理をどこで検知するかを決める。アプリ内の完了カウンターだけでは入口の失敗を拾えない。
- 集約:同じ窓のgood・bad・対象件数を全インスタンスで合計する。Podごとの成功率やp99を単純平均しない。
サーバー側の計測だけなら、ブラウザー側の通信失敗や画面操作の遅さは別途確認します。外形監視はユーザー操作の経路を補えますが、その少数の試行を実ユーザーの大量リクエストへ無条件に混ぜると指標の意味が変わります。異なる計測の役割を定義して併用します。
99.9%のエラーバジェットを件数で計算する
エラーバジェットは、目標を満たす範囲で許容するbadの量です。分母を1億件に固定した計算例では、許容不良率0.1%なので10万件。観測したbadが3万件なら30%を消費し、残り7万件です。これは分母が確定した場合の計算で、月の途中に未来のリクエスト数が確定するという意味ではありません。
# Python 3: exact arithmetic for a hypothetical request-based SLO
from fractions import Fraction
slo = Fraction(999, 1000)
eligible_requests = 100_000_000 # fixed denominator for this example
allowed_bad = eligible_requests * (1 - slo)
observed_bad = 30_000
print(int(allowed_bad)) # 100000
print(float(observed_bad / allowed_bad)) # 0.3 consumed
print(int(allowed_bad - observed_bad)) # 70000 remaining
error_ratio = Fraction(144, 10000) # 1.44%
burn_rate = error_ratio / (1 - slo)
print(float(burn_rate)) # 14.4
# Only with constant request volume across the 30-day period:
print(float(burn_rate * Fraction(1, 30 * 24))) # 0.02 of the budget直近30日というローリング窓では、時間が進むと過去のgoodとbadが窓から出て、分母も変わります。残り7万件を固定の残高として使い続けないようにします。リクエスト単位の目標と、時間単位の稼働率も別です。0.1%のリクエスト不良率を、そのまま許容停止時間へ変換することはできません。
バーンレートの意味:1.44%の不良率は14.4倍
バーンレートは 観測したbadの割合 / (1 - SLO) です。99.9%の目標なら、不良率1.44%は 0.0144 / 0.001 = 14.4 倍。異なる窓でも同じ定義で比較できますが、14.4倍という値だけでは、期間全体の予算を何%使ったかまでは分かりません。
30日=720時間を通じて毎時の対象件数が一定だと仮定すると、14.4倍が1時間続けば、期間予算の 14.4 / 720 = 2% を使います。流量が変わるなら、実際の消費は 窓内のbad件数 / ((1 - SLO) * 期間全体の対象件数) で確かめます。深夜の1時間とピークの1時間が、同じ不良率でも同じ予算を消費するとは限りません。
長い窓と短い窓を組み合わせて通知する
Google SRE Workbookの例では、30日・99.9%の目標に対して次の組み合わせを出発点にしています。数値はそのまま全サービスへ適用する推奨ではなく、流量と必要な対応時間に合わせて調整します。予算割合の時間換算には前節の流量条件を使っています。
| 長い窓 | 短い窓 | 両方で超えるバーンレート | 一定流量なら長い窓で使う予算 |
|---|---|---|---|
| 1時間 | 5分 | 14.4倍 | 2% |
| 6時間 | 30分 | 6倍 | 5% |
# Pseudocode: ratios aggregate eligible request counts across instances
# Each window must have eligible traffic and valid, fresh telemetry.
fast = bad_ratio_1h > 0.0144 and bad_ratio_5m > 0.0144
slow = bad_ratio_6h > 0.0060 and bad_ratio_30m > 0.0060
page = fast or slow
# Missing telemetry and zero traffic need separate handling.長い窓は影響の蓄積、短い窓は現在も悪化が続くかを見るために使います。短いバーストでも、両方の窓で閾値を超えれば通知されます。長い窓があるから短時間の障害を必ず無視するわけではありません。通知の重複抑制と復旧判定も含めて試験します。
低トラフィック・ゼロ件・欠測を分ける
1時間10件のうち1件失敗なら不良率は10%、99.9%目標で100倍です。少数の失敗で大きく動くため、同じ閾値でも通知の性質は高流量のサービスと異なります。単発の失敗でも重大な操作なら個別の監視を用意し、継続的な経路確認には合成リクエストを別指標で使うなど、影響に合わせます。
メトリクスで絞り、トレースで原因をたどる
通知からは、対象操作、評価窓、good/bad件数、現在と目標、直近の変更、調査手順へ進めるようにします。ルートごとの遅延・エラー・流量・飽和で影響を絞り、具体的な失敗はログや分散トレースで調べます。CPUやメモリは原因調査に使え、ディスク枯渇や証明書期限の予防監視も引き続き必要です。
メトリクスのラベルは、値の組み合わせごとに時系列を増やします。仮に20ルート×5状態×10 Podなら最大1,000通り。さらに1万ユーザーを掛けると最大1,000万通りです。実際には観測された組み合わせだけが生成されますが、ユーザーIDや生のURLを無制限に付けず、ルートテンプレートなどに限定します。ヒストグラムならバケットなどの系列も増えるため、別に見積もります。
トレースIDはメトリクスの通常ラベルへ追加せず、ログや対応するexemplarから調査へつなぎます。HTTPをまたぐ文脈はW3C Trace Contextに対応した計装で伝播させます。1つのトレース内でも各ホップのspanが異なるため、traceparent全体を固定IDとしてコピーし続ける実装にはしません。診断情報に認証トークンや個人情報を埋め込まないことも確認します。
通知を受けた人が何をするかまで検証する
- 正常、継続失敗、短いバースト、低流量、ゼロ件、欠測の時系列を使い、発火と解除を確かめる。
- アラートから対象経路と調査画面へ進み、直近の変更、外部依存、DB待ちを確認できるか試す。
- 切り戻し、負荷制限、依存先の切り替えなど、担当者が取れる対策と連絡経路を決める。
- 予算消費が大きいときにリリースをどう扱うか合意する。通知件数だけでなく、見逃した障害と不要な呼び出しから見直す。
- Google SRE — Service level indicators and objectives
- Google SRE Workbook — Alerting on SLOs
- Google SRE — Monitoring distributed systems
- Prometheus — Metric and label naming
- W3C — Trace Context