SLO/SLI設計とエラーバジェット運用をPrometheusで実践する
この記事でわかること
- SLI/SLOの設計手順と、ユーザー体験から逆算するSLI選択の考え方
- エラーバジェットの計算方法と、チーム間で合意するポリシー策定の進め方
- Prometheusを使ったMulti-Window Multi-Burn-Rate Alertsの実装方法
- Sloth・Pyrra・OpenSLOといったSLOツールの特徴と選定基準
- エラーバジェット枯渇時のリリース凍結・解除フローの設計パターン
対象読者
- 想定読者: SREやDevOpsに関心のあるバックエンドエンジニア・インフラエンジニア
-
必要な前提知識:
- Linux/コンテナ環境での基本的なサーバー運用経験
- Prometheus/Grafanaの基本操作(PromQLの基礎)
- KubernetesまたはDockerの基本概念
- HTTPステータスコードやレイテンシの基礎知識
結論・成果
SLO/SLI設計とエラーバジェット運用を適切に導入することで、開発速度と信頼性のバランスを定量的に管理できるようになります。Google SRE Workbookで推奨されているMulti-Window Multi-Burn-Rate Alertsは、従来の閾値ベースアラートと比較して検知精度(precision)とリセット時間の両方を改善し、アラートファティーグを大幅に軽減できることが示されています(Google SRE Workbook - Alerting on SLOs)。また、国内事例では、エラーバジェットベースのアラート導入によりMTTR(平均復旧時間)60%短縮を達成した報告もあります(SLO/SLI 2025 - 信頼性目標駆動の運用)。
この記事では、SLI/SLOの基本概念からPrometheusでの実装、エラーバジェットの組織的運用まで、段階的に解説していきます。
SLI/SLOの基本概念を理解する
SLI/SLOはGoogle発祥のSRE(Site Reliability Engineering)プラクティスの中核をなす概念です。まずは用語を整理しましょう。
SLI・SLO・SLA・エラーバジェットの関係
| 用語 | 正式名称 | 定義 | 例 |
|---|---|---|---|
| SLI | Service Level Indicator | サービス品質の定量的指標 | リクエスト成功率、P99レイテンシ |
| SLO | Service Level Objective | SLIに対する目標値 | 成功率 99.9%、P99 < 300ms |
| SLA | Service Level Agreement | SLO未達時の契約上の補償 | 稼働率99.95%未満で返金 |
| エラーバジェット | Error Budget | SLOの余裕分(= 1 - SLO) | 0.1%(月間約43分のダウン許容) |
ここで重要なのは、SLIは技術メトリクス、SLOは目標値、エラーバジェットはリスク許容量という関係です。SLAはビジネス契約であり、通常SLOよりも緩く設定します。
SLIの種類と選び方
Google SRE Workbookでは、システムの種類に応じて適切なSLIを選択することが推奨されています(Implementing SLOs)。
リクエスト駆動型サービス(API、Webアプリケーション):
| SLIカテゴリ | 測定内容 | PromQL例 |
|---|---|---|
| Availability | 成功リクエストの割合 | sum(rate(http_requests_total{code!~"5.."}[5m])) / sum(rate(http_requests_total[5m])) |
| Latency | 閾値内に完了したリクエストの割合 | histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) |
| Quality | 劣化なしレスポンスの割合 | フォールバック応答でない割合 |
パイプライン型システム(バッチ処理、ETL):
| SLIカテゴリ | 測定内容 | 例 |
|---|---|---|
| Freshness | データが許容時間内に更新された割合 | 最終更新から5分以内のレコード率 |
| Correctness | 正しい出力を生成した割合 | 処理結果の整合性チェック |
| Coverage | 処理対象データのうち実際に処理された割合 | 全レコード中の処理成功率 |
なぜSLI選択が重要か:
SLI選択を誤ると、「システムは正常だがユーザーは困っている」または「システム異常だがユーザーには影響がない」という乖離が生じます。たとえばCPU使用率やメモリ使用率は内部メトリクスであり、SLIとして適切ではありません。SLIはユーザーが直接体験する品質を測定すべきです(SLI、SLO、エラーバジェット導入の前に知っておきたいこと)。
注意: 最初のSLI/SLOは完璧でなくてよいです。Google SRE Workbookでも「Your first attempt at an SLI and SLO doesn't have to be correct; the most important goal is to get something in place and measured」と明記されています。まずは始めて、運用しながら改善しましょう。
CUJ(クリティカルユーザージャーニー)からSLIを導出する
SLI設計の出発点はCUJ(Critical User Journey)の特定です。これは、ユーザーがサービスで達成したい主要な行動シナリオを指します。
たとえばECサイトの場合を考えてみましょう。
CUJから導出したSLIとSLOの例:
| CUJ | SLI | SLO目標 |
|---|---|---|
| 商品検索 | 検索APIの成功率 | 99.9%(30日間) |
| 商品検索 | 検索APIのP99レイテンシ | 300ms以下 |
| 購入完了 | 決済APIの成功率 | 99.95%(30日間) |
| 購入完了 | 決済APIのP99レイテンシ | 1000ms以下 |
ハマりポイント: CUJを細かくしすぎると管理が複雑になります。最初は3〜5個のCUJに絞り、対応するSLIも各CUJあたり1〜2個に抑えましょう。Google SRE Workbookでも段階的に拡張することが推奨されています。
SLOとエラーバジェットを設計する
SLIを決定したら、次にSLO目標値を設定し、エラーバジェットを算出します。
SLO目標値の設定方法
初期SLO設定のアプローチは過去のパフォーマンスデータに基づくのが定石です(Implementing SLOs)。
ステップ1: 現状の計測
# SLO設定の前に、過去4週間のデータを確認する例(Python + Prometheus API)
# prometheus_client は pip install prometheus-api-client でインストール
import requests
from datetime import datetime, timedelta
PROMETHEUS_URL = "http://prometheus:9090"
QUERY = 'sum(rate(http_requests_total{code!~"5.."}[28d])) / sum(rate(http_requests_total[28d]))'
response = requests.get(
f"{PROMETHEUS_URL}/api/v1/query",
params={"query": QUERY},
timeout=30,
)
result = response.json()
if result["status"] == "success" and result["data"]["result"]:
current_availability = float(result["data"]["result"][0]["value"][1])
# 例: 0.99723 → 99.723%
print(f"過去28日間の可用性: {current_availability * 100:.3f}%")
# ステップ2: 有効数字2桁に切り捨て → 初期SLO候補
# 99.723% → 99.7% を初期SLOとして提案
proposed_slo = round(current_availability * 1000) / 1000
print(f"初期SLO候補: {proposed_slo * 100:.1f}%")
ステップ2: エラーバジェットの算出
SLO目標値が決まれば、エラーバジェットは自動的に算出されます。
| SLO目標 | エラーバジェット | 30日間の許容ダウンタイム | 30日間の許容エラー数(100万リクエスト/日) |
|---|---|---|---|
| 99% | 1% | 7時間12分 | 300,000件 |
| 99.5% | 0.5% | 3時間36分 | 150,000件 |
| 99.9% | 0.1% | 43分12秒 | 30,000件 |
| 99.95% | 0.05% | 21分36秒 | 15,000件 |
| 99.99% | 0.01% | 4分19秒 | 3,000件 |
よくある間違い: 最初から99.99%のような厳しいSLOを設定してしまうケースです。エラーバジェットが月間4分19秒しかないため、定期メンテナンスですら予算を消費してしまいます。Google SRE Workbookでは、まず現状のパフォーマンスから切り捨てた値を初期SLOとし、段階的に引き上げることを推奨しています。
エラーバジェットポリシーを策定する
エラーバジェットは「算出して終わり」ではなく、枯渇時のアクションを事前にポリシーとして定めることが最重要です(Error Budget Policy)。
典型的なエラーバジェットポリシーは以下の4段階で構成されます:
| バジェット残量 | ステータス | アクション |
|---|---|---|
| 50%以上 | Green | 通常の開発速度で機能リリース |
| 20〜50% | Yellow | デプロイ頻度を下げ、追加レビューを要求 |
| 1〜20% | Orange | 非クリティカルな機能デプロイを凍結 |
| 0%(枯渇) | Red | 全機能デプロイ凍結、信頼性回復に全力 |
ポリシー策定で合意すべき3者:
Google SRE Workbookでは、エラーバジェットポリシーの策定にあたり、以下の3者の合意が必須とされています:
- プロダクトマネージャー: SLOがユーザー体験として許容可能か確認
- 開発チーム: バジェット枯渇時のリリース凍結に同意
- SRE/運用チーム: SLOが過度な負荷なく防衛可能か確認
制約条件: エラーバジェットポリシーは事前合意が鍵です。バジェット枯渇後に「凍結するかどうか」を議論し始めると、チーム間の対立が生じやすくなります。HRMOSの事例でも、「エラーバジェット運用を開始する前に各関係者の合意を取り、ルール化する」ことの重要性が報告されています(円滑なエラーバジェット運用に向けた取り組み)。
凍結時に許容するリリースの定義
バジェット枯渇による凍結中でも、以下のリリースは許容するのが一般的です(円滑なエラーバジェット運用に向けた取り組み):
- 本番障害への緊急対応(hotfix)
- 信頼性回復のための改修(SLO違反の根本原因修正)
- 対外的に時期を約束しているリリース(事前にステークホルダーが合意済み)
- セキュリティパッチ
凍結解除の基準も事前に定めておきましょう。単にSLOが回復しただけでなく、ポストモーテムのアクションアイテム完了を解除条件に含めるアプローチもあります。
PrometheusでMulti-Window Multi-Burn-Rate Alertsを実装する
SLI/SLOを設計したら、次はアラートの実装です。Google SRE Workbookで推奨されているMulti-Window Multi-Burn-Rate Alertsは、SLOベースアラートの業界標準となっています(Alerting on SLOs)。
バーンレートとは
バーンレート(Burn Rate)は、エラーバジェットの消費速度を表す指標です。
- バーンレート 1x: 30日間でちょうどバジェットを使い切る速度
- バーンレート 10x: 30日分のバジェットを3日で使い切る速度
- バーンレート 14.4x: 30日分のバジェットを約2日で使い切る速度(=2%を1時間で消費)
従来の「エラー率 > X%」という閾値アラートでは、短時間のスパイクで過剰にアラートが発生するか、緩やかな劣化を見逃すかのトレードオフがありました。バーンレートアラートは「バジェット消費の速度」で判断するため、このトレードオフを解消できます。
Multi-Window Multi-Burn-Rate Alertsの構成
Google SRE Workbookの推奨構成は以下の3レベルです:
| 重要度 | ロングウィンドウ | ショートウィンドウ | バーンレート | 消費バジェット |
|---|---|---|---|---|
| Page(即時対応) | 1時間 | 5分 | 14.4x | 2% |
| Page(即時対応) | 6時間 | 30分 | 6x | 5% |
| Ticket(営業時間内対応) | 3日 | 6時間 | 1x | 10% |
なぜ2つのウィンドウを使うのか:
ロングウィンドウだけだと、問題が解消した後もアラートが残り続けます。ショートウィンドウを追加し、「両方の条件を同時に満たす場合のみ発火」とすることで、問題解消から約5分でアラートがリセットされます。
Prometheus Recording Rulesの実装
まず、各時間ウィンドウでのエラー率を事前計算するRecording Rulesを定義します。以下はGoogle公式サンプル(prometheus-slo-burn-example)を参考に、ECサイトの検索APIに適用した例です。
# prometheus/rules/slo_recording_rules.yml
# SLO: 検索API可用性 99.9%(30日間)
groups:
- name: slo_search_api_error_rates
# 各時間ウィンドウでのエラー率を事前計算
rules:
# 5分ウィンドウ(ショートウィンドウ: Page用)
- record: job:slo_errors_per_request:ratio_rate5m
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[5m]))
# 30分ウィンドウ(ショートウィンドウ: Page用)
- record: job:slo_errors_per_request:ratio_rate30m
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[30m]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[30m]))
# 1時間ウィンドウ(ロングウィンドウ: Page用)
- record: job:slo_errors_per_request:ratio_rate1h
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[1h]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[1h]))
# 6時間ウィンドウ(ロング/ショートウィンドウ兼用)
- record: job:slo_errors_per_request:ratio_rate6h
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[6h]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[6h]))
# 3日ウィンドウ(ロングウィンドウ: Ticket用)
- record: job:slo_errors_per_request:ratio_rate3d
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[3d]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[3d]))
# 28日ウィンドウ(エラーバジェット残量計算用)
- record: job:slo_errors_per_request:ratio_rate28d
expr: |
sum by (job) (rate(http_requests_total{job="search-api", code=~"5.."}[28d]))
/
sum by (job) (rate(http_requests_total{job="search-api"}[28d]))
- name: slo_search_api_error_budget
rules:
# エラーバジェット残量(%)
- record: job:error_budget:remaining
expr: |
1 - job:slo_errors_per_request:ratio_rate28d / (1 - 0.999)
labels:
slo: "search-api-availability"
Alerting Rulesの実装
Recording Rulesを使ったアラートルールを定義します。
# prometheus/rules/slo_alerting_rules.yml
# SLO: 99.9%(エラーバジェット = 0.001)
groups:
- name: slo_search_api_alerts
rules:
# Page: バーンレート14.4x(1時間ウィンドウ + 5分ウィンドウ)
# または バーンレート6x(6時間ウィンドウ + 30分ウィンドウ)
- alert: SearchApiHighErrorBurnRate
expr: |
(
job:slo_errors_per_request:ratio_rate1h{job="search-api"} > (14.4 * 0.001)
and
job:slo_errors_per_request:ratio_rate5m{job="search-api"} > (14.4 * 0.001)
)
or
(
job:slo_errors_per_request:ratio_rate6h{job="search-api"} > (6 * 0.001)
and
job:slo_errors_per_request:ratio_rate30m{job="search-api"} > (6 * 0.001)
)
labels:
severity: page
slo: "search-api-availability"
annotations:
summary: "検索APIのエラーバジェット消費速度が高い"
description: >
検索APIのエラー率がSLO 99.9%の許容範囲を超える速度で
バジェットを消費しています。即時対応が必要です。
runbook_url: "https://wiki.example.com/runbooks/search-api-slo"
# Ticket: バーンレート1x(3日ウィンドウ + 6時間ウィンドウ)
- alert: SearchApiSlowErrorBurnRate
expr: |
(
job:slo_errors_per_request:ratio_rate3d{job="search-api"} > (1 * 0.001)
and
job:slo_errors_per_request:ratio_rate6h{job="search-api"} > (1 * 0.001)
)
labels:
severity: ticket
slo: "search-api-availability"
annotations:
summary: "検索APIのエラーバジェットが緩やかに消費されている"
description: >
検索APIのエラー率がSLO 99.9%のバジェットを緩やかに
消費しています。営業時間内に調査してください。
なぜこの実装を選んだか:
-
Recording Rulesで事前計算: アラート評価時に毎回
rate()を計算すると、Prometheusへの負荷が高くなります。Recording Rulesで事前計算しておくことで、アラート評価が軽量になります -
14.4 * 0.001の計算:14.4はバーンレート、0.001はエラーバジェット(= 1 - 0.999)です。SLO目標を変更する場合はこの0.001を変更するだけで済みます
注意: このアプローチはリクエスト数が少ないサービスでは精度が低下します。1時間あたりのリクエスト数が1,000件未満の場合、統計的なノイズが大きくなるため、より長いウィンドウの使用やイベントベースのSLIへの切り替えを検討してください。
Grafanaダッシュボードでエラーバジェットを可視化する
アラートだけでなく、日常的にエラーバジェットの残量を可視化しておくことも重要です。以下はGrafanaダッシュボードで使用するPromQLクエリの例です。
# エラーバジェット残量(%表示)
(1 - job:slo_errors_per_request:ratio_rate28d{job="search-api"} / 0.001) * 100
# バーンレート(現在の消費速度)
job:slo_errors_per_request:ratio_rate1h{job="search-api"} / 0.001
# SLO達成状況(直近28日)
(1 - job:slo_errors_per_request:ratio_rate28d{job="search-api"}) * 100
SLOツールを活用して運用を自動化する
Recording RulesとAlerting Rulesを手動で書くのは、SLIの数が増えると管理が煩雑になります。ここでは、SLOの定義からPrometheusルールを自動生成するツールを紹介します。
主要SLOツールの比較
| ツール | 特徴 | UI | Kubernetes対応 | 開発状態 |
|---|---|---|---|---|
| Sloth | YAML定義からPrometheusルール自動生成 | Grafanaダッシュボード | CRD対応 | メンテナンスモード |
| Pyrra | Web UI付きのSLOオペレータ | 内蔵Web UI | CRD対応 | アクティブ開発中 |
| OpenSLO | ベンダー中立のSLO定義仕様 | なし(仕様のみ) | 間接的 | コミュニティ主導 |
| Nobl9 | SaaS型SLO管理プラットフォーム | フルUI | 間接的 | 商用 |
| Datadog SLO | Datadog統合SLO機能 | Datadog UI | 間接的 | 商用 |
SlothによるSLO定義の例
Slothを使うと、シンプルなYAML定義からMulti-Window Multi-Burn-Rate Alertsのルールが自動生成されます。
# slo/search-api.yml
version: "prometheus/v1"
service: "search-api"
labels:
team: "platform"
environment: "production"
slos:
- name: "search-api-availability"
objective: 99.9 # SLO目標: 99.9%
description: "検索APIの可用性SLO"
sli:
events:
error_query: sum(rate(http_requests_total{job="search-api",code=~"5.."}[{{.window}}]))
total_query: sum(rate(http_requests_total{job="search-api"}[{{.window}}]))
alerting:
name: SearchApiAvailability
labels:
team: "platform"
annotations:
runbook_url: "https://wiki.example.com/runbooks/search-api-slo"
page_alert:
labels:
severity: page
ticket_alert:
labels:
severity: ticket
# SlothでPrometheusルールを生成
# Slothのインストール: https://github.com/slok/sloth#install
sloth generate -i slo/search-api.yml -o prometheus/rules/generated_slo_rules.yml
# 生成されたルールをPrometheusに反映
# prometheus.ymlのrule_filesに追加後、リロード
curl -X POST http://prometheus:9090/-/reload
Slothが自動生成するルールには、先ほど手動で定義したRecording RulesとAlerting Rulesがすべて含まれます。SLIの数が増えても、YAML定義を追加するだけで対応できるため、運用負荷が大幅に下がります。
PyrraによるKubernetes CRDの例
Kubernetes環境であれば、PyrraのCRDとして定義するアプローチもあります。PyrraはWeb UIが内蔵されているため、Grafanaダッシュボードを別途構築する必要がありません。
# k8s/pyrra-slo.yml
apiVersion: pyrra.dev/v1alpha1
kind: ServiceLevelObjective
metadata:
name: search-api-availability
namespace: monitoring
labels:
team: platform
pyrra.dev/team: platform
spec:
target: "99.9" # SLO目標
window: 28d # 評価ウィンドウ
description: "検索APIの可用性SLO"
indicator:
ratio:
errors:
metric: http_requests_total{job="search-api",code=~"5.."}
total:
metric: http_requests_total{job="search-api"}
# PyrraをKubernetesにデプロイ(Helm chart使用)
helm repo add pyrra https://pyrra-dev.github.io/helm-charts
helm install pyrra pyrra/pyrra -n monitoring --create-namespace
# SLOリソースを適用
kubectl apply -f k8s/pyrra-slo.yml
# Pyrra Web UIにアクセス
kubectl port-forward -n monitoring svc/pyrra 9099:9099
# http://localhost:9099 でSLOダッシュボードを確認
OpenSLOによるベンダー中立な定義
特定のツールに依存しない形でSLOを定義したい場合、OpenSLO仕様が有用です。OpenSLOはCNCF(Cloud Native Computing Foundation)傘下で策定されたベンダー中立のYAML仕様で、GitOpsワークフローとの親和性が高いのが特徴です。
# openslo/search-api-slo.yml
apiVersion: openslo/v1
kind: SLO
metadata:
name: search-api-availability
displayName: 検索API可用性
spec:
description: 検索APIの可用性目標
service: search-api
budgetingMethod: Occurrences
objectives:
- displayName: 可用性
target: 0.999 # 99.9%
ratioMetrics:
good:
source: prometheus
queryType: promql
query: sum(rate(http_requests_total{job="search-api",code!~"5.."}[{{.window}}]))
total:
source: prometheus
queryType: promql
query: sum(rate(http_requests_total{job="search-api"}[{{.window}}]))
timeWindow:
- duration: 28d
isRolling: true
ツール選定のトレードオフ:
- Sloth: シンプルで導入しやすいが、開発者がメンテナンスモードと宣言しており、新機能追加は期待できない
- Pyrra: アクティブに開発されWeb UIもあるが、Kubernetes環境が前提
- OpenSLO: ベンダーロックインを避けられるが、単体では機能せず別途ツールとの組み合わせが必要
よくある問題と解決方法
SLO/SLI運用で発生しがちな問題と対策をまとめます。
| 問題 | 原因 | 解決方法 |
|---|---|---|
| アラートが多すぎて対応しきれない | 閾値ベースアラートのまま | Multi-Window Multi-Burn-Rate Alertsに移行 |
| エラーバジェットがすぐ枯渇する | SLO目標が厳しすぎる | 過去データに基づいて現実的な目標に調整 |
| チーム間でSLO解釈が異なる | ポリシーが文書化されていない | エラーバジェットポリシーを事前に策定・合意 |
| SLOがビジネス指標と乖離 | CPUなど内部メトリクスをSLIに使用 | CUJからSLIを導出し直す |
| Recording Rulesの管理が煩雑 | 手動でルールを記述 | Sloth/Pyrra等のSLOツールで自動生成 |
| バジェット枯渇後に凍結判断が遅れる | 凍結基準・解除基準が未定義 | 事前にポリシー文書で合意を取る |
| リクエスト数が少なくアラート精度が低い | 統計的サンプル不足 | ウィンドウを広げるか、イベントベースSLIに変更 |
まとめと次のステップ
まとめ:
- SLI設計はCUJ(クリティカルユーザージャーニー) から逆算し、ユーザーが体験する品質を測定すべき
- SLO目標は過去のパフォーマンスデータに基づいて設定し、段階的に引き上げる
- エラーバジェットポリシーは事前に3者(PM・開発・SRE)の合意を得て文書化する
- PrometheusアラートはMulti-Window Multi-Burn-Rate Alertsを採用し、アラートノイズを削減する
- SLO定義が増えたらSloth/Pyrra/OpenSLO等のツールで自動化する
次にやるべきこと:
- 自分のサービスのCUJを3〜5個洗い出し、対応するSLIを定義する
- 過去4週間のデータから初期SLO目標値を設定する
- エラーバジェットポリシーのドラフトを作成し、ステークホルダーと合意する
- Prometheusに Recording Rules + Alerting Rulesを導入し、Grafanaで可視化する
参考
- Google SRE Workbook - Implementing SLOs
- Google SRE Workbook - Alerting on SLOs
- Google SRE Workbook - Error Budget Policy
- prometheus-slo-burn-example(Google公式サンプル)
- SLI、SLO、エラーバジェット導入の前に知っておきたいこと(sreake.com)
- 円滑なエラーバジェット運用に向けた取り組み(Visional Engineering Blog)
- Sloth - Prometheus SLO Generator
- Pyrra - Making SLOs with Prometheus manageable
- OpenSLO - Open specification for SLOs
- SLO/SLI 2025 - 信頼性目標駆動の運用
注意: この記事はAI(Claude Code)により自動生成されました。内容の正確性については複数の情報源で検証していますが、実際の利用時は公式ドキュメントもご確認ください。