observability・8分で読める
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の条件
- ユーザー体験に直結: ユーザーが実際に感じる品質を反映
- 測定可能: 明確に数値化できる
- 制御可能: チームの努力で改善できる
- シンプル: 複雑すぎない、理解しやすい
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に含めるべき要素
- サービスレベル: 保証する品質指標
- 測定方法: どのように測定するか
- 対象範囲: 何が対象で何が除外されるか
- ペナルティ: 未達成時の補償
- 例外事項: 不可抗力などの除外規定
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
まとめ
重要ポイント
- SLI: 何を測定するか(指標)
- SLO: どのレベルを目指すか(内部目標)
- SLA: 何を約束するか(外部契約)
- エラーバジェット: どれだけ失敗できるか(イノベーションの余地)
実践ステップ
ステップ1: SLIの選定
- ユーザー体験に直結する指標を選ぶ
- 可用性、レイテンシ、エラー率が基本
ステップ2: SLOの設定
- 現状を測定し、現実的な目標を設定
- 100%を目指さない(99.9%〜99.95%が妥当)
ステップ3: 測定の自動化
- CloudWatch、Datadogで自動計測
- ダッシュボードで可視化
ステップ4: エラーバジェット管理
- 残量に応じてリリース判断
- チーム間で合意形成
ステップ5: 継続的改善
- 四半期ごとにSLOを見直し
- ユーザーフィードバックを反映
参考資料
- Google SRE Book: https://sre.google/sre-book/table-of-contents/
- Service Level Objectives: https://sre.google/sre-book/service-level-objectives/
- Monitoring Distributed Systems: https://sre.google/sre-book/monitoring-distributed-systems/
- Google SRE Workbook: https://sre.google/workbook/table-of-contents/
- Implementing SLOs: https://sre.google/workbook/implementing-slos/
SLI・SLO・SLAを正しく理解し、適切に設定・管理することで、サービスの信頼性と開発速度のバランスを取りながら、ユーザーに価値を提供し続けることができます。