observability8分で読める

SLA・SLO・SLI完全ガイド:サービス品質を定義・測定・管理する

SLA、SLO、SLIの違いと実践的な設定方法を解説。エラーバジェット、計算式、具体例を含む、Google SREの考え方に基づいた信頼性管理の完全ガイド。

#SRE#SLA#SLO#SLI#信頼性#モニタリング#運用

SLA・SLO・SLI完全ガイド

SLA(Service Level Agreement)、SLO(Service Level Objective)、SLI(Service Level Indicator)は、サービスの信頼性を定義・測定・管理するための重要な概念です。


基本概念

SLI(Service Level Indicator)- サービスレベル指標

定義: サービスのパフォーマンスを測定する具体的な指標。

  • 何を測定するか: サービスの品質を数値化したもの
  • : リクエスト成功率、レイテンシ、稼働率
  • 形式: 通常はパーセンテージや時間で表現
例:
- 成功したリクエストの割合: 99.9%
- 500msec以内に完了したリクエストの割合: 95%
- サービスが利用可能だった時間の割合: 99.95%

SLO(Service Level Objective)- サービスレベル目標

定義: SLIに対して設定する目標値。

  • 何を定義するか: 「どれくらいのSLIを達成すべきか」という内部目標
  • : 「可用性99.9%を維持する」
  • 特徴: 社内チーム向けの目標、SLAよりも厳しく設定
例:
- 可用性 SLO: 99.9%(月間ダウンタイム43.8分以内)
- レイテンシ SLO: P95で500ms以内
- エラー率 SLO: 0.1%未満

SLA(Service Level Agreement)- サービスレベル合意

定義: 顧客と交わす、サービス品質に関する契約・約束。

  • 何を約束するか: 「このレベルのサービスを提供します」という外部への契約
  • : 「可用性99.5%を保証、未達成時は返金」
  • 特徴: 法的拘束力、ペナルティ規定を含む
例:
- 月間稼働率99.5%を保証
- 未達成時は利用料金の10%を返金
- サポート応答時間: 1時間以内

SLI・SLO・SLAの関係

          厳しい                                  緩い
            ↓                                      ↓
    [内部目標] SLO ≧ [外部約束] SLA ≧ [実測値] SLI

例:
- SLO: 99.9%(内部目標)
- SLA: 99.5%(顧客への約束)
- SLI: 99.95%(実際の測定値)

この場合:
✓ SLI (99.95%) > SLO (99.9%) → 目標達成
✓ SLI (99.95%) > SLA (99.5%) → 契約遵守

なぜSLOがSLAより厳しいのか

  • バッファの確保: SLAを違反する前に対策を打つため
  • 早期警告: SLO違反をアラートのトリガーにする
  • 継続的改善: より高い基準で品質を維持

ゴールデンシグナルとSLI

Google SREが提唱する「4つのゴールデンシグナル」に基づいたSLIの設計:

1. レイテンシ(Latency)

リクエストの応答時間。

推奨SLI:

成功したリクエストの95%が500ms以内に完了
成功したリクエストの99%が1000ms以内に完了

計算式:

P95レイテンシ = 全リクエストを速い順に並べた時の95%点の値

2. トラフィック(Traffic)

システムに対する需要の量。

推奨SLI:

1秒あたりのリクエスト数(RPS)
1秒あたりのトランザクション数(TPS)

3. エラー(Errors)

失敗したリクエストの割合。

推奨SLI:

成功したリクエストの割合: 99.9%
= エラー率: 0.1%未満

計算式:

成功率 = (成功したリクエスト数 / 総リクエスト数) × 100
エラー率 = (失敗したリクエスト数 / 総リクエスト数) × 100

4. サチュレーション(Saturation)

システムリソースの使用状況。

推奨SLI:

CPU使用率: 80%未満
メモリ使用率: 80%未満
ディスク使用率: 85%未満

SLIの選び方

良いSLIの条件

  1. ユーザー体験に直結: ユーザーが実際に感じる品質を反映
  2. 測定可能: 明確に数値化できる
  3. 制御可能: チームの努力で改善できる
  4. シンプル: 複雑すぎない、理解しやすい

SLIの例:Webサービス

種類SLI測定方法
可用性成功したリクエストの割合(2xx,3xx ステータス数 / 全リクエスト数) × 100
レイテンシP95レイテンシCloudWatch、Datadogで測定
品質エラー率(5xx ステータス数 / 全リクエスト数) × 100
スループット秒間処理リクエスト数CloudWatch Metricsで測定

SLIの例:バッチ処理

種類SLI測定方法
完了率成功したバッチの割合(成功したバッチ数 / 実行したバッチ数) × 100
処理時間バッチの実行時間処理完了時刻 - 処理開始時刻
鮮度データの最新性現在時刻 - データ更新時刻

SLIの例:データベース

種類SLI測定方法
可用性接続成功率(成功した接続数 / 接続試行数) × 100
レイテンシクエリ応答時間RDS Performance Insightsで測定
正確性データ整合性チェック定期的な整合性検証

SLOの設定方法

ステップ1: ユーザーの期待を理解する

質問:

  • ユーザーは何を期待しているか?
  • どのくらいのダウンタイムなら許容されるか?
  • どの程度のレスポンス速度が必要か?

ステップ2: 現在のパフォーマンスを測定する

実施:

  • 過去3〜6ヶ月のメトリクスを分析
  • 現実的な目標値を設定
  • ピーク時とオフピーク時を考慮

ステップ3: SLOを定義する

フォーマット:

[SLI] は [期間] において [目標値] を達成する

例:
- リクエストの99%は30日間において500ms以内に完了する
- APIの可用性は1ヶ月において99.9%を維持する
- エラー率は1週間において0.1%未満を維持する

ステップ4: エラーバジェットを計算する

エラーバジェット: SLOで許容される失敗の量。

例:SLO 99.9%の場合

月間(30日 = 43,200分):
- 許容ダウンタイム: 43.2分(0.1%)
- これが「エラーバジェット」

月間100万リクエストの場合:
- 許容エラー数: 1,000リクエスト(0.1%)

SLO設定のベストプラクティス

1. 100%を目指さない

理由:

  • 100%可用性は現実的ではない
  • 過度な投資が必要
  • イノベーションの阻害

推奨:

サービスタイプ別の推奨SLO:

- ミッションクリティカル: 99.95%〜99.99%
- ビジネスクリティカル: 99.9%〜99.95%
- 一般的なサービス: 99%〜99.9%
- 内部ツール: 95%〜99%

2. 複数のSLOを設定する

例:ECサイト:

- 可用性 SLO: 99.9%
- レイテンシ SLO: P95 < 500ms、P99 < 1000ms
- エラー率 SLO: < 0.1%
- 決済成功率 SLO: 99.95%

3. 期間を明確にする

推奨:

  • 短期: 7日、30日(アラート用)
  • 長期: 四半期、年次(ビジネス報告用)

4. 段階的な目標設定

現状 → 第1段階 → 第2段階 → 理想

例:
- 現状: 可用性 99.5%
- 第1段階(3ヶ月後): 99.7%
- 第2段階(6ヶ月後): 99.9%
- 理想(1年後): 99.95%

エラーバジェット

エラーバジェットとは

SLOで許容される「失敗の余裕」。

エラーバジェット = 100% - SLO

例:SLO 99.9%の場合
エラーバジェット = 100% - 99.9% = 0.1%

エラーバジェットの使い方

1. イノベーションとリスクのバランス

エラーバジェットが残っている → 新機能をリリースできる
エラーバジェットが枯渇 → 安定化作業に集中

2. 意思決定の基準

エラーバジェット残量アクション
80%以上残積極的に新機能リリース、実験的な機能追加
50-80%残通常のリリースサイクル
20-50%残リリース頻度を下げる、安定性重視
20%未満新機能リリース凍結、安定化作業に集中
枯渇リリース完全停止、障害対応のみ

3. チーム間の調整

開発チーム:

  • 新機能の追加
  • アーキテクチャの変更
  • パフォーマンス改善

SREチーム:

  • インフラの安定性
  • 監視とアラート
  • 障害対応

合意事項:

エラーバジェットポリシー:

1. エラーバジェットが50%以上残っている場合
   - 週2回のデプロイ可能
   - 新機能の追加OK

2. エラーバジェットが50%未満の場合
   - 週1回のデプロイに制限
   - バグ修正のみ

3. エラーバジェットが枯渇した場合
   - デプロイ凍結
   - 安定化作業に専念
   - 次の測定期間まで新機能なし

エラーバジェットの計算例

例1: 可用性ベース

SLO: 99.9%(月間)
月間: 30日 = 43,200分

エラーバジェット = 43,200分 × 0.1% = 43.2分

月の途中で20分のダウンタイムが発生:
- 消費: 20分
- 残量: 23.2分(53.7%残)
- 判断: 通常のリリースサイクルを継続

例2: リクエストベース

SLO: エラー率 0.1%未満(週間)
週間リクエスト数: 1,000,000

エラーバジェット = 1,000,000 × 0.1% = 1,000リクエスト

月曜日に500エラーが発生:
- 消費: 500リクエスト
- 残量: 500リクエスト(50%残)
- 判断: リリース頻度を下げる、慎重にテスト

SLAの設計

SLAに含めるべき要素

  1. サービスレベル: 保証する品質指標
  2. 測定方法: どのように測定するか
  3. 対象範囲: 何が対象で何が除外されるか
  4. ペナルティ: 未達成時の補償
  5. 例外事項: 不可抗力などの除外規定

SLAの例:SaaSサービス

## サービスレベル契約(SLA)

### 1. 稼働率保証

月間稼働率: 99.5%以上を保証

### 2. 測定方法

稼働率 = (月間総時間 - ダウンタイム) / 月間総時間 × 100

### 3. ダウンタイムの定義

- HTTPステータス 5xxエラーが1分間継続
- APIエンドポイントが応答しない状態が1分間継続

### 4. 除外事項

以下はダウンタイムに含まれません:
- 事前通知した定期メンテナンス(月次、最大4時間)
- お客様側のネットワーク障害
- お客様の利用規約違反による停止
- 不可抗力(天災、戦争、テロ等)

### 5. 補償

| 月間稼働率 | サービスクレジット |
|-----------|------------------|
| 99.5%未満99.0%以上 | 月額利用料の10% |
| 99.0%未満95.0%以上 | 月額利用料の25% |
| 95.0%未満 | 月額利用料の50% |

### 6. クレジット申請

- 申請期限: 該当月の翌月末まで
- 申請方法: サポートチケット経由
- 適用: 翌月の請求から減額

SLA設計のベストプラクティス

1. 現実的な目標

悪い例:
- 99.999%(ファイブナイン)を約束 → 年間5分しか許されない

良い例:
- 99.5%を約束 → 月間3.6時間の余裕
- SLO 99.9%で内部管理 → バッファあり

2. 明確な測定方法

悪い例:
- 「高い可用性を提供します」→ 曖昧

良い例:
- 「AWS CloudWatchで測定した月間稼働率99.5%以上」→ 明確

3. 段階的なペナルティ

推奨:
- 99.5%未満: 10%返金
- 99.0%未満: 25%返金
- 95.0%未満: 50%返金

非推奨:
- 99.5%未満: 100%返金 → 過度なリスク

CloudWatchでのSLI測定

可用性SLIの実装

import boto3
from datetime import datetime, timedelta

cloudwatch = boto3.client('cloudwatch')

# ALBのメトリクスから可用性を計算
def calculate_availability_sli(load_balancer_name, start_time, end_time):
    # 成功リクエスト数(2xx, 3xx)
    success_metrics = cloudwatch.get_metric_statistics(
        Namespace='AWS/ApplicationELB',
        MetricName='HTTPCode_Target_2XX_Count',
        Dimensions=[{'Name': 'LoadBalancer', 'Value': load_balancer_name}],
        StartTime=start_time,
        EndTime=end_time,
        Period=3600,
        Statistics=['Sum']
    )
    
    # 総リクエスト数
    total_metrics = cloudwatch.get_metric_statistics(
        Namespace='AWS/ApplicationELB',
        MetricName='RequestCount',
        Dimensions=[{'Name': 'LoadBalancer', 'Value': load_balancer_name}],
        StartTime=start_time,
        EndTime=end_time,
        Period=3600,
        Statistics=['Sum']
    )
    
    success_count = sum([point['Sum'] for point in success_metrics['Datapoints']])
    total_count = sum([point['Sum'] for point in total_metrics['Datapoints']])
    
    availability = (success_count / total_count) * 100 if total_count > 0 else 0
    
    return {
        'availability': availability,
        'success_count': success_count,
        'total_count': total_count,
        'error_count': total_count - success_count
    }

# 月間SLIの計算
end_time = datetime.now()
start_time = end_time - timedelta(days=30)

result = calculate_availability_sli('my-load-balancer', start_time, end_time)

print(f"可用性SLI: {result['availability']:.3f}%")
print(f"成功リクエスト: {result['success_count']:,}")
print(f"総リクエスト: {result['total_count']:,}")
print(f"エラー: {result['error_count']:,}")

# SLO判定
SLO = 99.9
if result['availability'] >= SLO:
    print(f"✓ SLO {SLO}%達成")
else:
    print(f"✗ SLO {SLO}%未達成")
    deficit = SLO - result['availability']
    print(f"不足: {deficit:.3f}%")

レイテンシSLIの実装

def calculate_latency_sli(load_balancer_name, start_time, end_time):
    # P95レイテンシの取得
    latency_metrics = cloudwatch.get_metric_statistics(
        Namespace='AWS/ApplicationELB',
        MetricName='TargetResponseTime',
        Dimensions=[{'Name': 'LoadBalancer', 'Value': load_balancer_name}],
        StartTime=start_time,
        EndTime=end_time,
        Period=3600,
        Statistics=['Average'],
        ExtendedStatistics=['p95', 'p99']
    )
    
    # P95レイテンシの平均
    p95_values = [point['ExtendedStatistics']['p95'] 
                  for point in latency_metrics['Datapoints']]
    avg_p95 = sum(p95_values) / len(p95_values) if p95_values else 0
    
    return {
        'p95_latency_ms': avg_p95 * 1000,  # 秒からミリ秒に変換
        'datapoints': len(p95_values)
    }

result = calculate_latency_sli('my-load-balancer', start_time, end_time)

print(f"P95レイテンシ: {result['p95_latency_ms']:.2f}ms")

# SLO判定(P95 < 500ms)
SLO_LATENCY = 500
if result['p95_latency_ms'] <= SLO_LATENCY:
    print(f"✓ レイテンシSLO {SLO_LATENCY}ms達成")
else:
    print(f"✗ レイテンシSLO {SLO_LATENCY}ms未達成")

エラーバジェット追跡

def calculate_error_budget(sli, slo, period_minutes):
    """
    エラーバジェットの計算と残量追跡
    
    Args:
        sli: 実際のSLI値(%)
        slo: 目標SLO値(%)
        period_minutes: 測定期間(分)
    """
    # エラーバジェット(分)
    error_budget_minutes = period_minutes * (100 - slo) / 100
    
    # 消費したバジェット(分)
    consumed_minutes = period_minutes * (100 - sli) / 100
    
    # 残量(分)
    remaining_minutes = error_budget_minutes - consumed_minutes
    
    # 残量率(%)
    remaining_percentage = (remaining_minutes / error_budget_minutes) * 100
    
    return {
        'error_budget_minutes': error_budget_minutes,
        'consumed_minutes': consumed_minutes,
        'remaining_minutes': remaining_minutes,
        'remaining_percentage': remaining_percentage,
        'status': get_budget_status(remaining_percentage)
    }

def get_budget_status(remaining_percentage):
    if remaining_percentage >= 80:
        return 'HEALTHY - 積極的なリリース可能'
    elif remaining_percentage >= 50:
        return 'GOOD - 通常のリリースサイクル'
    elif remaining_percentage >= 20:
        return 'CAUTION - リリース頻度を下げる'
    elif remaining_percentage > 0:
        return 'WARNING - 安定化作業に注力'
    else:
        return 'CRITICAL - リリース凍結'

# 月間エラーバジェットの計算
SLI = 99.95  # 実測値
SLO = 99.9   # 目標値
PERIOD = 30 * 24 * 60  # 30日(分)

budget = calculate_error_budget(SLI, SLO, PERIOD)

print(f"エラーバジェット総量: {budget['error_budget_minutes']:.2f}分")
print(f"消費: {budget['consumed_minutes']:.2f}分")
print(f"残量: {budget['remaining_minutes']:.2f}分")
print(f"残量率: {budget['remaining_percentage']:.1f}%")
print(f"ステータス: {budget['status']}")

ダッシュボードとアラート

CloudWatchダッシュボード構成例

{
  "widgets": [
    {
      "type": "metric",
      "properties": {
        "title": "可用性SLI(月間)",
        "metrics": [
          ["AWS/ApplicationELB", "RequestCount", {"stat": "Sum", "label": "総リクエスト"}],
          [".", "HTTPCode_Target_2XX_Count", {"stat": "Sum", "label": "成功"}]
        ],
        "period": 86400,
        "stat": "Average",
        "region": "ap-northeast-1",
        "yAxis": {
          "left": {
            "min": 0
          }
        },
        "annotations": {
          "horizontal": [
            {
              "label": "SLO: 99.9%",
              "value": 99.9,
              "fill": "above"
            },
            {
              "label": "SLA: 99.5%",
              "value": 99.5,
              "fill": "below"
            }
          ]
        }
      }
    },
    {
      "type": "metric",
      "properties": {
        "title": "エラーバジェット残量",
        "metrics": [
          ["CustomMetrics", "ErrorBudgetRemaining", {"stat": "Average"}]
        ],
        "period": 3600,
        "stat": "Average",
        "region": "ap-northeast-1",
        "yAxis": {
          "left": {
            "min": 0,
            "max": 100
          }
        },
        "annotations": {
          "horizontal": [
            {
              "label": "CRITICAL",
              "value": 20,
              "fill": "below"
            },
            {
              "label": "WARNING",
              "value": 50,
              "fill": "below"
            }
          ]
        }
      }
    }
  ]
}

SLO違反のアラート設定

# CloudFormation例
SLOViolationAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: "SLO-Violation-Availability"
    AlarmDescription: "可用性SLOが99.9%を下回った"
    MetricName: AvailabilitySLI
    Namespace: CustomMetrics
    Statistic: Average
    Period: 3600
    EvaluationPeriods: 3
    Threshold: 99.9
    ComparisonOperator: LessThanThreshold
    TreatMissingData: breaching
    AlarmActions:
      - !Ref SNSTopicForSLO

ErrorBudgetDepletionAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: "Error-Budget-Critical"
    AlarmDescription: "エラーバジェット残量が20%未満"
    MetricName: ErrorBudgetRemaining
    Namespace: CustomMetrics
    Statistic: Average
    Period: 3600
    EvaluationPeriods: 1
    Threshold: 20
    ComparisonOperator: LessThanThreshold
    TreatMissingData: breaching
    AlarmActions:
      - !Ref SNSTopicForCritical

まとめ

重要ポイント

  1. SLI: 何を測定するか(指標)
  2. SLO: どのレベルを目指すか(内部目標)
  3. SLA: 何を約束するか(外部契約)
  4. エラーバジェット: どれだけ失敗できるか(イノベーションの余地)

実践ステップ

ステップ1: SLIの選定
- ユーザー体験に直結する指標を選ぶ
- 可用性、レイテンシ、エラー率が基本

ステップ2: SLOの設定
- 現状を測定し、現実的な目標を設定
- 100%を目指さない(99.9%〜99.95%が妥当)

ステップ3: 測定の自動化
- CloudWatch、Datadogで自動計測
- ダッシュボードで可視化

ステップ4: エラーバジェット管理
- 残量に応じてリリース判断
- チーム間で合意形成

ステップ5: 継続的改善
- 四半期ごとにSLOを見直し
- ユーザーフィードバックを反映

参考資料

SLI・SLO・SLAを正しく理解し、適切に設定・管理することで、サービスの信頼性と開発速度のバランスを取りながら、ユーザーに価値を提供し続けることができます。

RK

1997年生まれ

ITエンジニア

インフラ・SRE

SLA・SLO・SLI完全ガイド:サービス品質を定義・測定・管理する