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