Skip to content
Published on

SLI/SLO/Error Budget基盤の信頼性エンジニアリング実践ガイド

Authors
  • Name
    Twitter
SLI SLO Error Budget

はじめに

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サービスレベルの測定指標成功リクエスト比率、レイテンシ分布エンジニアリング
SLOSLIに対する目標値30日可用性99.9%以上エンジニアリング + プロダクト
SLASLO + 契約的結果99.95%未達時クレジット返金ビジネス + 法務
Error Budget100% - SLO0.1% = 月43分ダウンタイム許容エンジニアリング

SLI指標選定戦略

サービスタイプ別SLI

サービスタイプによって適切なSLIが異なる。Google SRE Workbookでは以下のように分類している。

サービスタイプ主要SLI測定方法
Request-driven(API、Web)可用性、レイテンシ成功応答比率、p50/p99応答時間
Pipeline(バッチ、ETL)鮮度、正確性データ処理遅延、結果精度
Storage(DB、キャッシュ)耐久性、スループットデータ損失率、秒当たり読み書き数
Streaming(Kafka、Pub/Sub)レイテンシ、スループットエンドツーエンド遅延、秒当たりメッセージ数

SLI選定の原則

  1. ユーザージャーニー(CUJ)ベース: ログイン、検索、決済などの重要なユーザージャーニーごとにSLIを定義する。
  2. 測定容易性を優先: 複雑な計装よりも既存のログやメトリクスから抽出可能なSLIを先に選択する。
  3. Syntheticモニタリングの併用: サーバー側メトリクスだけではCDNキャッシュヒット率やクライアントレンダリング時間を測定できないため、Synthetic Monitoringを併用する。
  4. 多段階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設定プロセス

  1. 現在のパフォーマンス測定: 最低2週間の実データを収集し、サービスの実際の信頼性を把握する。
  2. ユーザー期待の調査: ユーザーが実際に認識する品質レベルを確認する。内部ツールと外部サービスでは期待値が異なる。
  3. コスト便益分析: 99.9%から99.99%に引き上げるコストが、それに見合うビジネス価値を持つか評価する。
  4. ステークホルダーの合意: プロダクトマネージャー、エンジニアリングリード、経営陣が全員同意する数値を設定する。
  5. 反復的な調整: 最初の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の状況を一目で把握できるように構成する。主要パネルは以下の通りだ。

  1. 現在のSLI値(Stat Panel): 現在の可用性SLIを大きな数字で表示する。閾値カラーでステータスを直感的に示す。
  2. Error Budget残存率(Gauge Panel): Error Budgetの残り比率をゲージで表示する。50%以下で黄色、25%以下で赤に変わる。
  3. Burn Rate推移(Time Series Panel): 時間経過に伴うBurn Rateの変化をグラフで表示する。アラート閾値を水平線で示す。
  4. 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消費イベントに連動しているか

参考資料