- Authors
- Name
- はじめに
- SLI/SLO/SLAの概念整理
- SLI指標選定戦略
- SLO数値の設定
- Error Budgetポリシー
- Burn Rateアラート
- Prometheusベースの実装
- Grafanaダッシュボード
- 組織導入戦略
- 失敗事例と教訓
- 運用チェックリスト
- 参考資料

はじめに
Prometheusでメトリクスを収集し、Alertmanagerでアラートを構成した。しかし障害が発生するたびに「どこまでが許容範囲なのか?」という質問に答えるのが難しい。CPU使用率80%でアラートを設定したが、ユーザー体感品質とは無関係なアラートが繰り返され、チームはAlert Fatigueに苦しんでいる。
GoogleのSREチームは、この問題を根本的に解決するためにSLI(Service Level Indicator)、SLO(Service Level Objective)、Error Budgetというフレームワークを確立した。このフレームワークの核心はシンプルだ。「ユーザー視点でサービス品質を測定し、許容可能な障害範囲を定量化し、信頼性と開発速度のバランスをデータで決定する。」
本記事では、SLI/SLO/SLAの概念整理から始め、SLI指標の選定、SLO数値の設定、Error Budgetポリシー、Burn Rateアラート、Prometheusベースの実装、Grafanaダッシュボード、組織導入戦略まで、プロダクションサービスの信頼性管理パイプライン全体をコードと共に構築する。
SLI/SLO/SLAの概念整理
SLI(Service Level Indicator)
SLIはサービスレベルを示す定量的指標だ。Google SRE本では、SLIを**「良いイベント数 / 全イベント数」**の比率として定義している。例えば「全HTTPリクエストのうち200ms以内に応答したリクエストの割合」が一つのSLIとなる。SLIは常に0%から100%の間の値を持つ。
SLO(Service Level Objective)
SLOはSLIに対する目標値だ。「応答時間SLIが30日間で99.9%以上であること」がSLOの例だ。SLOは内部エンジニアリングチームが設定し、ユーザーの期待とエンジニアリングコストのバランス点を表す。100%のSLOは現実的に不可能であり、目指すべきでもない。
SLA(Service Level Agreement)
SLAはSLOに法的・契約的結果を付与したものだ。「可用性99.95%未満の場合、クレジット返金」のように、違反時に金銭的補償や契約解除条件が含まれる。SLAはビジネス契約であり、SLOはエンジニアリング目標だ。SLOは常にSLAより厳格であるべきで、SLAが99.9%であればSLOは99.95%以上に設定して内部的により高い基準を維持する。
Error Budget
Error BudgetはSLOから派生する概念だ。SLOが99.9%であればError Budgetは0.1%だ。30日基準で計算すると約43分のダウンタイムが許容される。Error Budgetは「どれだけ障害が許容されるか」を定量化したもので、これにより機能開発速度と信頼性のトレードオフをデータベースで管理できる。
| 概念 | 定義 | 例 | 主体 |
|---|---|---|---|
| SLI | サービスレベルの測定指標 | 成功リクエスト比率、レイテンシ分布 | エンジニアリング |
| SLO | SLIに対する目標値 | 30日可用性99.9%以上 | エンジニアリング + プロダクト |
| SLA | SLO + 契約的結果 | 99.95%未達時クレジット返金 | ビジネス + 法務 |
| Error Budget | 100% - SLO | 0.1% = 月43分ダウンタイム許容 | エンジニアリング |
SLI指標選定戦略
サービスタイプ別SLI
サービスタイプによって適切なSLIが異なる。Google SRE Workbookでは以下のように分類している。
| サービスタイプ | 主要SLI | 測定方法 |
|---|---|---|
| Request-driven(API、Web) | 可用性、レイテンシ | 成功応答比率、p50/p99応答時間 |
| Pipeline(バッチ、ETL) | 鮮度、正確性 | データ処理遅延、結果精度 |
| Storage(DB、キャッシュ) | 耐久性、スループット | データ損失率、秒当たり読み書き数 |
| Streaming(Kafka、Pub/Sub) | レイテンシ、スループット | エンドツーエンド遅延、秒当たりメッセージ数 |
SLI選定の原則
- ユーザージャーニー(CUJ)ベース: ログイン、検索、決済などの重要なユーザージャーニーごとにSLIを定義する。
- 測定容易性を優先: 複雑な計装よりも既存のログやメトリクスから抽出可能なSLIを先に選択する。
- Syntheticモニタリングの併用: サーバー側メトリクスだけではCDNキャッシュヒット率やクライアントレンダリング時間を測定できないため、Synthetic Monitoringを併用する。
- 多段階SLO: 一つのSLIに複数の閾値を設定する。「90%のリクエストは100ms以内、99%のリクエストは400ms以内」のように二つの目標を同時に追跡する。
SLO数値の設定
SLO数値別許容ダウンタイム
SLO数値が高くなるほど、許容ダウンタイムは指数関数的に減少する。
| SLO | 月間Error Budget | 年間Error Budget |
|---|---|---|
| 99% | 7時間18分 | 3日15時間 |
| 99.5% | 3時間39分 | 1日19時間 |
| 99.9% | 43分50秒 | 8時間46分 |
| 99.95% | 21分55秒 | 4時間23分 |
| 99.99% | 4分23秒 | 52分36秒 |
SLO設定プロセス
- 現在のパフォーマンス測定: 最低2週間の実データを収集し、サービスの実際の信頼性を把握する。
- ユーザー期待の調査: ユーザーが実際に認識する品質レベルを確認する。内部ツールと外部サービスでは期待値が異なる。
- コスト便益分析: 99.9%から99.99%に引き上げるコストが、それに見合うビジネス価値を持つか評価する。
- ステークホルダーの合意: プロダクトマネージャー、エンジニアリングリード、経営陣が全員同意する数値を設定する。
- 反復的な調整: 最初のSLOは保守的に始め、四半期ごとにレビューして調整する。
Error Budgetポリシー
Error Budgetポリシーは、Error Budget消費時に取るべき具体的な行動を文書化したものだ。Google SRE Workbookでは書面化されたポリシーを推奨している。
Error Budgetポリシーの例
# error-budget-policy.yaml
error_budget_policy:
service: payment-api
slo_window: 30d
slo_target: 99.9%
thresholds:
- level: green
budget_remaining: '>50%'
actions:
- 通常の機能開発を継続
- 週次SLOレビューミーティング
- level: yellow
budget_remaining: '25%-50%'
actions:
- 新機能リリース前に信頼性レビュー必須
- 技術的負債の解消作業を並行実施
- 日次SLOレビューミーティング
- level: orange
budget_remaining: '10%-25%'
actions:
- 新機能リリースを停止
- エンジニアリング時間の50%以上を信頼性作業に投入
- 障害原因分析(Postmortem)を即時実行
- level: red
budget_remaining: '<10%'
actions:
- 全機能開発を凍結
- 全エンジニアリングリソースを信頼性復旧に集中
- 経営陣へのエスカレーション
- SLO未達の根本原因が解消されるまで凍結を維持
Error Budget消費時の対応プロセス
Error Budgetが消費された際の対応は、組織の信頼性文化を示すリトマス試験だ。核心原則は以下の通りだ。
- 機能凍結(Feature Freeze): Error Budget消費時は信頼性復旧が最優先だ。
- Postmortem必須: すべてのError Budget消費イベントに対して非難なしのPostmortemを実施する。
- 自動化の強化: 手動作業(Toil)が原因の場合、自動化を優先的に実装する。
- SLOの再検討: 繰り返しError Budgetを消費する場合、SLO自体が攻撃的すぎないか検討する。
Burn Rateアラート
Burn Rateの概念
Burn RateはError Budgetをどれだけ速く消費しているかを示す倍率だ。Burn Rate 1はSLOウィンドウ(例:30日)の間にError Budgetをちょうど使い切る速度を意味する。Burn Rate 10は30日分の予算を3日で使い切る速度だ。
アラート方式の比較
| アラート方式 | 長所 | 短所 |
|---|---|---|
| 閾値ベース(エラー率1%超過) | 設定が簡単 | ユーザー影響と無関係なアラートが多い |
| Burn Rate単一ウィンドウ | SLOと直接連動 | 短いスパイクに過剰反応する |
| Multi-Window Multi-Burn-Rate | 精密な検出が可能 | 設定が複雑 |
Multi-Window Multi-Burn-Rateアラート
Google SRE Workbookで推奨される方式だ。二つのウィンドウ(長いウィンドウ + 短いウィンドウ)を同時にチェックし、長いウィンドウは実際のトレンドを反映し、短いウィンドウはすでに復旧した問題に対するアラートを防止する。
# multi-window-burn-rate-alerts.yaml
# Google SRE Workbook推奨アラート設定
groups:
- name: slo-burn-rate-alerts
rules:
# ページアラート: 2%の予算を1時間以内に消費(Burn Rate 14.4)
- alert: SLOBurnRateHigh_Page
expr: |
(
sli:error_ratio:rate1h > (14.4 * 0.001)
and
sli:error_ratio:rate5m > (14.4 * 0.001)
)
for: 2m
labels:
severity: page
annotations:
summary: 'Error budget burn rate is very high'
description: 'Service is consuming error budget 14.4x faster than normal. 2% of 30-day budget will be consumed in 1 hour.'
# ページアラート: 5%の予算を6時間以内に消費(Burn Rate 6)
- alert: SLOBurnRateMedium_Page
expr: |
(
sli:error_ratio:rate6h > (6 * 0.001)
and
sli:error_ratio:rate30m > (6 * 0.001)
)
for: 5m
labels:
severity: page
annotations:
summary: 'Error budget burn rate is elevated'
description: 'Service is consuming error budget 6x faster than normal. 5% of 30-day budget will be consumed in 6 hours.'
# チケットアラート: 10%の予算を3日以内に消費(Burn Rate 1)
- alert: SLOBurnRateSlow_Ticket
expr: |
(
sli:error_ratio:rate3d > (1 * 0.001)
and
sli:error_ratio:rate6h > (1 * 0.001)
)
for: 30m
labels:
severity: ticket
annotations:
summary: 'Error budget burn rate indicates slow degradation'
description: 'Service is steadily consuming error budget. 10% of 30-day budget will be consumed in 3 days.'
Prometheusベースの実装
SLI Recording Rules
SLIを効率的に計算するためにRecording Rulesを使用する。様々な時間ウィンドウに対してエラー比率を事前計算しておくと、アラートルールで再利用できる。
# sli-recording-rules.yaml
groups:
- name: sli-recording-rules
interval: 30s
rules:
# 全リクエスト中のエラー比率(様々なウィンドウ)
- record: sli:error_ratio:rate5m
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
- record: sli:error_ratio:rate30m
expr: |
sum(rate(http_requests_total{status=~"5.."}[30m]))
/
sum(rate(http_requests_total[30m]))
- record: sli:error_ratio:rate1h
expr: |
sum(rate(http_requests_total{status=~"5.."}[1h]))
/
sum(rate(http_requests_total[1h]))
- record: sli:error_ratio:rate6h
expr: |
sum(rate(http_requests_total{status=~"5.."}[6h]))
/
sum(rate(http_requests_total[6h]))
- record: sli:error_ratio:rate3d
expr: |
sum(rate(http_requests_total{status=~"5.."}[3d]))
/
sum(rate(http_requests_total[3d]))
# レイテンシSLI: 200ms以内の応答比率
- record: sli:latency_good_ratio:rate5m
expr: |
sum(rate(http_request_duration_seconds_bucket{le="0.2"}[5m]))
/
sum(rate(http_request_duration_seconds_count[5m]))
- record: sli:latency_good_ratio:rate1h
expr: |
sum(rate(http_request_duration_seconds_bucket{le="0.2"}[1h]))
/
sum(rate(http_request_duration_seconds_count[1h]))
Error Budget残量の計算
# Error Budget残存率(30日ウィンドウ、SLO 99.9%)
# 結果が1なら100%残存、0なら完全消費
(
1 - (
sum(increase(http_requests_total{status=~"5.."}[30d]))
/
sum(increase(http_requests_total[30d]))
)
- 0.999
) / 0.001
上記のクエリは、直近30日間の実際のエラー比率を求め、SLO目標値(0.999)を引いて、残りのError Budgetを全Error Budget(0.001)で割ったものだ。結果が0.5であればError Budgetの50%が残っていることを意味する。
SLOレポーティングスクリプト
#!/usr/bin/env python3
"""SLOレポート生成スクリプト"""
import requests
from datetime import datetime, timedelta
PROMETHEUS_URL = "http://prometheus:9090"
SLO_CONFIGS = [
{
"name": "payment-api-availability",
"sli_query": 'sum(rate(http_requests_total{job="payment-api",status!~"5.."}[30d])) / sum(rate(http_requests_total{job="payment-api"}[30d]))',
"slo_target": 0.999,
"window_days": 30,
},
{
"name": "payment-api-latency",
"sli_query": 'sum(rate(http_request_duration_seconds_bucket{job="payment-api",le="0.2"}[30d])) / sum(rate(http_request_duration_seconds_count{job="payment-api"}[30d]))',
"slo_target": 0.995,
"window_days": 30,
},
]
def query_prometheus(query: str) -> float:
"""Prometheus instant queryの実行"""
resp = requests.get(
f"{PROMETHEUS_URL}/api/v1/query",
params={"query": query},
)
result = resp.json()["data"]["result"]
if not result:
return 0.0
return float(result[0]["value"][1])
def generate_report():
"""SLOレポートの生成"""
print(f"=== SLO Report ({datetime.now().strftime('%Y-%m-%d %H:%M')}) ===\n")
for config in SLO_CONFIGS:
current_sli = query_prometheus(config["sli_query"])
slo_target = config["slo_target"]
error_budget_total = 1 - slo_target
error_budget_consumed = max(0, slo_target - current_sli)
error_budget_remaining = max(
0, (error_budget_total - error_budget_consumed) / error_budget_total
)
status = "OK" if current_sli >= slo_target else "VIOLATED"
budget_pct = error_budget_remaining * 100
print(f"Service: {config['name']}")
print(f" SLI (current): {current_sli:.4%}")
print(f" SLO (target): {slo_target:.4%}")
print(f" Status: {status}")
print(f" Error Budget: {budget_pct:.1f}% remaining")
if budget_pct < 25:
print(f" WARNING: Error budget below 25%!")
print()
if __name__ == "__main__":
generate_report()
Grafanaダッシュボード
SLOダッシュボードの構成
Grafanaダッシュボードは、SLOの状況を一目で把握できるように構成する。主要パネルは以下の通りだ。
- 現在のSLI値(Stat Panel): 現在の可用性SLIを大きな数字で表示する。閾値カラーでステータスを直感的に示す。
- Error Budget残存率(Gauge Panel): Error Budgetの残り比率をゲージで表示する。50%以下で黄色、25%以下で赤に変わる。
- Burn Rate推移(Time Series Panel): 時間経過に伴うBurn Rateの変化をグラフで表示する。アラート閾値を水平線で示す。
- Error Budget消費予測(Time Series Panel): 現在のBurn Rateが維持された場合、Error Budgetが完全に消費される予想日を表示する。
# grafana-slo-dashboard.json(パネル構成の概要)
panels:
- title: 'Current Availability SLI'
type: stat
targets:
- expr: '1 - sli:error_ratio:rate30d'
legendFormat: 'Availability'
thresholds:
- value: 0.999
color: green
- value: 0.995
color: yellow
- value: 0.99
color: red
- title: 'Error Budget Remaining'
type: gauge
targets:
- expr: |
clamp_min(
(0.001 - sli:error_ratio:rate30d) / 0.001,
0
)
legendFormat: 'Budget Remaining'
min: 0
max: 1
thresholds:
- value: 0.5
color: green
- value: 0.25
color: yellow
- value: 0
color: red
- title: 'Burn Rate (1h window)'
type: timeseries
targets:
- expr: 'sli:error_ratio:rate1h / 0.001'
legendFormat: 'Burn Rate (1h)'
overrides:
- matcher: 'Burn Rate Threshold'
properties:
- id: custom.lineStyle
value: dash
組織導入戦略
段階的導入ロードマップ
SLI/SLOは技術的な実装だけでは成功しない。組織全体の合意と文化の変革が必要だ。
第1段階 - パイロット(1〜2ヶ月)
- 最も重要なサービス1〜2つを選定する。
- 既存のメトリクスから抽出可能な簡単なSLIから始める。
- SLOは現在のパフォーマンスよりやや低く設定し、達成可能な目標から始める。
第2段階 - 拡大(3〜6ヶ月)
- パイロット結果を基に主要サービスへ拡大する。
- Error Budgetポリシーを策定し、ステークホルダーの合意を確保する。
- Burn Rateアラートを本番環境に適用する。
第3段階 - 成熟(6〜12ヶ月)
- すべてのユーザー向けサービスにSLOを適用する。
- SLOをインシデントレビュー、キャパシティプランニング、リリース管理に統合する。
- 四半期ごとのSLOレビュープロセスを定例化する。
成功の核心要因
- 経営陣のスポンサーシップ: SLOベースの意思決定は機能開発の凍結を含むため、経営陣の支持が不可欠だ。
- プロダクトマネージャーの参加: SLO数値の決定にPMが必ず参加すべきだ。エンジニアだけの指標になると失敗する。
- 段階的アプローチ: 最初から完璧なSLOを目指さない。「不完全だが有用」は「完璧だが出荷されない」に勝る。
- 自動化への投資: SLOレポート生成、Error Budget追跡、Burn Rateアラートを自動化し、運用負荷を最小化する。
失敗事例と教訓
事例1: 過度に攻撃的なSLO
あるチームが外部SLAのない内部サービスに99.99%のSLOを設定した。月間Error Budgetはわずか4分23秒で、通常のデプロイさえ不可能だった。デプロイのたびに数秒のダウンタイムが発生し、即座にError Budgetが消費されて機能開発が事実上停止した。解決策は、SLOを99.9%に引き下げ、無停止デプロイ(Blue-Green、Canary)を導入することだった。
事例2: Burn Rate設定不良によるAlert Fatigue
Burn Rateアラートを導入したが、短いウィンドウ(5分)のみを使用したため、瞬間的なエラースパイクのたびにアラートが発生した。1日に数十件のアラートが発生し、オンコールエンジニアがアラートを無視し始めた。Multi-Window方式に切り替え、ページアラートとチケットアラートを分離することで解決した。
事例3: Error Budget消費時のポリシー不在
Error Budgetが消費されたが「機能凍結」ポリシーがなかったため、開発チームは新機能のリリースを続けた。結果として障害が繰り返され、ユーザー離脱が発生した。Error Budgetポリシーを書面で策定し、経営陣の承認を得てポリシーの実行力を確保した後にようやく問題が解決された。
運用チェックリスト
プロダクションにSLI/SLO/Error Budgetを導入する際に確認すべき項目を整理する。
- 重要ユーザージャーニー(CUJ)別にSLIが定義されているか
- SLIがPrometheus Recording Rulesで自動計算されているか
- SLO数値についてエンジニアリングとプロダクトチームが合意しているか
- Error Budgetポリシーが書面で文書化されているか
- Multi-Window Multi-Burn-Rateアラートが構成されているか
- ページアラート(即時対応)とチケットアラート(営業時間対応)が分離されているか
- GrafanaダッシュボードでSLI、Error Budget残存率、Burn Rateを確認できるか
- SLOレポートが週次・月次で自動生成されているか
- Error Budget消費時の機能凍結プロセスが経営陣の承認を受けているか
- 四半期ごとのSLOレビューミーティングがスケジュールに含まれているか
- PostmortemプロセスがError Budget消費イベントに連動しているか
参考資料
- Google SRE Book - Service Level Objectives
- Google SRE Workbook - Implementing SLOs
- Google SRE Workbook - Alerting on SLOs
- Google SRE Workbook - Error Budget Policy
- Google Cloud Blog - SRE Fundamentals: SLIs vs SLOs vs SLAs
- Sloth - Prometheus SLO Generator
- SLODLC Handbook - SLO Development Life Cycle
- Grafana Cloud - Introduction to SLO