SLO
SLO(Service Level Objectives)完全ガイド — 信頼性目標の設計・実装・運用
はじめに
SLO(Service Level Objectives)は、サービスの信頼性を定量的に定義・管理するためのフレームワークである。GoogleのSRE(Site Reliability Engineering)から生まれた概念で、「どの程度の信頼性で十分か」をデータに基づいて決定し、エンジニアリングリソースの配分を最適化する。
SLOの核心は、100%の信頼性は不可能であり、目指すべきでもないという認識にある。99.999%の可用性と99.9%の可用性の差は、ユーザーが認識できる範囲を超えていることが多く、その差を維持するコストは指数関数的に増加する。SLOはこのトレードオフを定量的に管理するメカニズムである。
本記事では、SLI/SLOの設計原則、具体的な計測手法、エラーバジェットの運用、バーンレートアラート、SLOドキュメント、ツールチェーン、組織への導入戦略まで、SLOの全容を体系的に解説する。
第1章: SLOの基本フレームワーク
1.1 SLI → SLO → SLA → エラーバジェットの関係
┌─────────────────────────────────────────────────────────┐
│ │
│ SLI (Service Level Indicator) │
│ 「何を測るか」— サービス品質の定量的指標 │
│ 例: 成功リクエスト率、P99レイテンシ │
│ │
│ ↓ │
│ │
│ SLO (Service Level Objective) │
│ 「どの水準を目指すか」— 内部のエンジニアリング目標 │
│ 例: 可用性 >= 99.9%(30日間ローリング) │
│ │
│ ↓ │
│ │
│ SLA (Service Level Agreement) │
│ 「顧客に何を約束するか」— 法的拘束力のある契約 │
│ 例: 可用性 >= 99.5%(違反時はクレジット返金) │
│ ※ SLA < SLO(SLOはSLAより厳しく設定すべき) │
│ │
│ ↓ │
│ │
│ エラーバジェット = 1 - SLO │
│ 「どこまで失敗を許容するか」— イノベーションの余地 │
│ 例: 0.1%のリクエストが失敗しても許容 │
│ │
└─────────────────────────────────────────────────────────┘
1.2 なぜ100%を目指さないのか
100%可用性を目指す場合の問題:
1. コストの指数的増加
99% → $X
99.9% → $10X
99.99% → $100X
99.999% → $1000X+
2. イノベーションの停滞
- 変更を一切入れないのが最も安全
- しかしビジネスは進化を求める
3. ユーザーの認知限界
- ユーザーはISP、ネットワーク、端末の問題もある
- サービスが99.999%でも、ユーザー体験は99.9%以下かもしれない
4. 依存サービスの制約
- 依存するサービスが99.9%なら、自サービスも99.9%が上限
- 直列の依存: 99.9% × 99.9% × 99.9% = 99.7%
適切な信頼性 = ユーザーの期待を満たす最低限の水準
→ これがSLOの本質
1.3 SLOの設計原則
原則1: ユーザーの視点で定義する
❌ "CPU使用率が80%以下"(インフラ視点)
✅ "リクエストの99.9%が200ms以内に応答"(ユーザー視点)
原則2: 測定可能で明確にする
❌ "サービスが高速であること"(曖昧)
✅ "P95レイテンシが500ms以下のリクエストが99%以上"(明確)
原則3: 達成可能な目標にする
❌ 実績が99.95%なのにSLO 99.999%を設定(非現実的)
✅ 実績99.95%に対してSLO 99.9%を設定(現実的+改善余地)
原則4: シンプルに保つ
❌ 20個のSLIに対して各SLOを定義(複雑すぎる)
✅ 3-5個の最も重要なSLIにSLOを定義(管理可能)
原則5: 定期的に見直す
- 四半期ごとにSLOの妥当性をレビュー
- ビジネス要件の変化に対応
- ユーザーからのフィードバックを反映
第2章: SLIの設計と計測
2.1 SLIの4つのカテゴリ(The Four Golden Signals準拠)
┌─────────────────────────────────────────────────────────┐
│ 1. 可用性(Availability) │
│ 「リクエストが正常に処理されたか」 │
│ │
│ SLI = 成功リクエスト数 / 全リクエスト数 │
│ │
│ 成功の定義: │
│ - HTTP: status < 500 │
│ - gRPC: status = OK │
│ - カスタム: ビジネスロジックに基づく成功判定 │
│ │
│ 除外すべきもの: │
│ - ヘルスチェックリクエスト │
│ - 内部モニタリングリクエスト │
│ - ロードバランサーのプローブ │
├─────────────────────────────────────────────────────────┤
│ 2. レイテンシ(Latency) │
│ 「リクエストがどれだけ速く処理されたか」 │
│ │
│ SLI = 閾値以内のリクエスト数 / 全リクエスト数 │
│ │
│ 複数の閾値を設定: │
│ - P50 (中央値): ユーザーの半数の体験 │
│ - P95: ほとんどのユーザーの体験 │
│ - P99: テールレイテンシ(最悪ケースの指標) │
│ │
│ 注意: 平均値は使わない(外れ値に影響される) │
├─────────────────────────────────────────────────────────┤
│ 3. 品質/正確性(Quality/Correctness) │
│ 「レスポンスの内容は正しいか」 │
│ │
│ SLI = 正確なレスポンス数 / 全レスポンス数 │
│ │
│ 例: │
│ - 検索結果が正しいか │
│ - レコメンデーションが劣化していないか │
│ - データが最新か(鮮度 / Freshness) │
├─────────────────────────────────────────────────────────┤
│ 4. スループット/飽和度(Throughput/Saturation) │
│ 「システムがどの程度の負荷を処理できるか」 │
│ │
│ SLI = 実際のスループット / 期待されるスループット │
│ または: キューの待ち時間 │
└─────────────────────────────────────────────────────────┘
2.2 SLI計測のアーキテクチャ
計測ポイントの選択:
① クライアント側(最もユーザーに近い)
┌──────┐
│Client│──── 計測ポイント①
└──┬───┘
│
② ロードバランサー(推奨)
┌──┴───┐
│ LB │──── 計測ポイント②(推奨: ユーザー視点に最も近い)
└──┬───┘
│
③ アプリケーション
┌──┴───┐
│ App │──── 計測ポイント③
└──┬───┘
│
④ データベース
┌──┴───┐
│ DB │──── 計測ポイント④(サーバー視点)
└──────┘
推奨: ②ロードバランサーで計測
理由: ユーザーに最も近く、アプリケーション障害も検知できる
2.3 具体的なSLI計測例
# Prometheus メトリクスベースの SLI 定義
# 可用性SLI
availability_sli:
good_events: |
sum(rate(http_requests_total{status!~"5.."}[5m]))
total_events: |
sum(rate(http_requests_total[5m]))
formula: good_events / total_events
# レイテンシSLI (P99 < 1000ms)
latency_sli:
good_events: |
sum(rate(http_request_duration_seconds_bucket{le="1.0"}[5m]))
total_events: |
sum(rate(http_request_duration_seconds_count[5m]))
formula: good_events / total_events
# Splunk SPL ベースの SLI 計算
# 可用性SLI(30日間ローリング)
index=web_logs earliest=-30d
| stats count(eval(status<500)) AS good, count AS total
| eval availability_sli = round(good / total * 100, 4)
# レイテンシSLI(P95 < 500ms)
index=web_logs earliest=-30d
| stats count(eval(response_time<=500)) AS good, count AS total
| eval latency_sli = round(good / total * 100, 4)
第3章: SLOの設定と文書化
3.1 SLOドキュメントテンプレート
# SLO Document: Payment API
service:
name: "Payment API"
owner: "Payment Team"
description: "顧客の決済処理を行うAPI"
dependencies:
- "Database (PostgreSQL)"
- "Payment Gateway (Stripe)"
- "Fraud Detection Service"
slos:
# SLO 1: 可用性
- name: "Availability"
description: "決済APIが正常に応答する割合"
sli:
type: "availability"
good_event: "HTTP status < 500"
valid_event: "All HTTP requests (excluding health checks)"
measurement_point: "Load Balancer access logs"
objective:
target: 99.95%
window: "30-day rolling"
error_budget:
total: "0.05% of requests"
monthly_estimate: "~2,160 failed requests (based on 4.3M requests/month)"
rationale: >
決済APIは収益に直結するため、高い可用性が求められる。
99.95%は月間約22分のダウンタイムに相当し、
ユーザー影響を最小限に抑えつつ、改善・変更の余地を確保する。
# SLO 2: レイテンシ(P50)
- name: "Latency P50"
description: "リクエストの50%が処理される時間"
sli:
type: "latency"
threshold: "200ms"
good_event: "response_time <= 200ms"
valid_event: "All successful HTTP requests (status < 500)"
objective:
target: 99%
window: "30-day rolling"
rationale: "大多数のユーザーにとって快適なレスポンスタイム"
# SLO 3: レイテンシ(P99)
- name: "Latency P99"
description: "リクエストの99%が処理される時間"
sli:
type: "latency"
threshold: "2000ms"
good_event: "response_time <= 2000ms"
objective:
target: 99.9%
window: "30-day rolling"
rationale: "テールレイテンシを2秒以内に抑え、最悪ケースのユーザー体験を保証"
error_budget_policy:
review_cadence: "Weekly in SRE standup, Monthly in service review"
thresholds:
green:
condition: "remaining > 50%"
actions: ["Normal operations"]
yellow:
condition: "25% < remaining <= 50%"
actions: ["Review upcoming changes for risk", "Prioritize reliability tasks"]
orange:
condition: "5% < remaining <= 25%"
actions: ["Critical fixes only", "50%+ time on reliability"]
red:
condition: "remaining <= 5%"
actions: ["Feature freeze", "Full focus on reliability", "Escalate to VP Eng"]
stakeholders:
- role: "SRE Team"
responsibility: "SLO monitoring, alerting, incident response"
- role: "Development Team"
responsibility: "Feature development within error budget, bug fixes"
- role: "Product Manager"
responsibility: "Prioritization decisions based on error budget status"
- role: "VP Engineering"
responsibility: "Escalation point for Red status"
review_history:
- date: "2024-01-15"
change: "Initial SLO document"
- date: "2024-04-01"
change: "Adjusted availability target from 99.9% to 99.95% based on Q1 data"
3.2 SLOウィンドウの選択
ローリングウィンドウ vs カレンダーウィンドウ:
ローリングウィンドウ(推奨):
- 「過去30日間」のように、常に直近の期間を対象
- 月初にリセットされない
- 障害の影響がウィンドウから外れるまで残る
例: 30日間ローリング
1/15の障害 → 2/14まで影響が残る
→ より継続的な改善のインセンティブ
カレンダーウィンドウ:
- 「2024年1月」のように、固定期間を対象
- 月初にバジェットがリセット
例: 月次カレンダー
1/30の障害 → 2/1にバジェットリセット
→ 月末の障害が「許される」リスク
推奨: 30日間ローリングウィンドウ
- SLO Report: 月次で報告
- SLO Alert: リアルタイムで監視
第4章: エラーバジェットとバーンレートアラート
4.1 エラーバジェットの計算
基本計算:
エラーバジェット(割合) = 1 - SLO目標
エラーバジェット(絶対値) = 全リクエスト数 × (1 - SLO目標)
例: SLO = 99.9%、月間リクエスト = 10,000,000
エラーバジェット = 10,000,000 × 0.001 = 10,000リクエスト
消費状況の計算:
消費済み = 実際のエラー数 / エラーバジェット × 100%
残量 = 100% - 消費済み
時間ベースの計算:
SLO = 99.9%、30日間ウィンドウ
許容ダウンタイム = 30日 × 24時間 × 60分 × 0.001 = 43.2分
4.2 バーンレート(Burn Rate)
バーンレート = 実際のエラーレート / SLOが許容するエラーレート
例: SLO = 99.9%(許容エラーレート = 0.1%)
現在のエラーレート = 0.5%
バーンレート = 0.5% / 0.1% = 5x
バーンレートの解釈:
1x → 30日でちょうどバジェットを使い切る(正常)
2x → 15日でバジェットを使い切る(やや危険)
5x → 6日でバジェットを使い切る(要対応)
14.4x → 2日でバジェットを使い切る(緊急)
720x → 1時間でバジェットを使い切る(クリティカル)
4.3 マルチウィンドウ・マルチバーンレートアラート
Google SRE Workbookが推奨するアラート戦略。
# Prometheus アラートルール
groups:
- name: slo-burn-rate-alerts
rules:
# ページ(即時対応): 短期的な高バーンレート
# 1時間で2%のバジェットを消費(バーンレート14.4x)
- alert: SLOBurnRateCritical
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[1h]))
/ sum(rate(http_requests_total[1h]))
) > (14.4 * 0.001)
AND
(
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
) > (14.4 * 0.001)
for: 2m
labels:
severity: critical
annotations:
summary: "Critical: Error budget burning at 14.4x rate"
description: "Budget exhaustion in ~2 days. Immediate action required."
# ページ: 中期的な高バーンレート
# 6時間で5%のバジェットを消費(バーンレート6x)
- alert: SLOBurnRateHigh
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[6h]))
/ sum(rate(http_requests_total[6h]))
) > (6 * 0.001)
AND
(
sum(rate(http_requests_total{status=~"5.."}[30m]))
/ sum(rate(http_requests_total[30m]))
) > (6 * 0.001)
for: 5m
labels:
severity: warning
# チケット(次営業日対応): 長期的なゆるやかな消費
# 3日間で10%のバジェットを消費(バーンレート1x)
- alert: SLOBurnRateSlow
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[3d]))
/ sum(rate(http_requests_total[3d]))
) > (1 * 0.001)
for: 1h
labels:
severity: info
マルチウィンドウの意図:
長期ウィンドウ(1h, 6h, 3d): トレンドの検出
→ 一時的なスパイクでは発火しない
短期ウィンドウ(5m, 30m): 現在進行中の問題の確認
→ 過去の問題で発火しない(問題が解決済みの場合)
両方を組み合わせることで:
✅ 本当の問題でのみアラート発火
❌ 一時的なスパイクでの誤報を防止
❌ 解決済み問題でのアラート残留を防止
第5章: SLOツールチェーンとダッシュボード
5.1 SLOツールの比較
| ツール | 種類 | 特徴 |
|---|---|---|
| Prometheus + Grafana | OSS | メトリクスベース、柔軟なアラート |
| Sloth | OSS | PrometheusベースのSLO生成ツール |
| OpenSLO | OSS標準 | SLO定義のオープン標準仕様 |
| Datadog SLOs | SaaS | GUI操作、統合モニタリング |
| Google Cloud SLO | SaaS | GCPネイティブ、Istio連携 |
| Splunk ITSI | SaaS | SPLベース、ビジネスサービス連携 |
| Nobl9 | SaaS | SLO専用プラットフォーム |
| Dynatrace SLOs | SaaS | AIベースの自動SLO |
5.2 OpenSLO仕様
# OpenSLO v1.0 仕様
apiVersion: openslo/v1
kind: SLO
metadata:
name: payment-api-availability
displayName: "Payment API Availability"
spec:
service: payment-api
description: "Payment API should be available 99.95% of the time"
budgetingMethod: Occurrences
objectives:
- displayName: "Availability"
target: 0.9995
op: gte
value: 1
ratioMetrics:
good:
source: prometheus
queryType: promql
query: sum(rate(http_requests_total{service="payment-api",status!~"5.."}[5m]))
total:
source: prometheus
queryType: promql
query: sum(rate(http_requests_total{service="payment-api"}[5m]))
timeWindow:
- duration: 30d
isRolling: true
alertPolicies:
- alertPolicyRef: payment-api-burn-rate
5.3 Sloth(Prometheus SLO Generator)
# sloth.yaml
version: "prometheus/v1"
service: "payment-api"
labels:
owner: "payment-team"
tier: "tier-1"
slos:
- name: "requests-availability"
objective: 99.95
description: "Payment API availability"
sli:
events:
error_query: sum(rate(http_requests_total{service="payment-api",status=~"5.."}[{{.window}}]))
total_query: sum(rate(http_requests_total{service="payment-api"}[{{.window}}]))
alerting:
name: PaymentAPIAvailability
labels:
team: payment
annotations:
runbook: "https://wiki.example.com/runbooks/payment-api"
page_alert:
labels:
severity: critical
ticket_alert:
labels:
severity: warning
# Slothの実行(Prometheusルール生成)
$ sloth generate -i sloth.yaml -o prometheus-rules.yaml
5.4 SLOダッシュボードの設計
┌──────────────────────────────────────────────────┐
│ SLO Dashboard - Payment API │
├──────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Availability │ │ Latency P50 │ │ Latency P99 │ │
│ │ 99.97% │ │ 99.5% │ │ 99.92% │ │
│ │ SLO: 99.95% │ │ SLO: 99% │ │ SLO: 99.9% │ │
│ │ ✅ Met │ │ ✅ Met │ │ ✅ Met │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Error Budget Remaining │ │
│ │ ████████████████████░░░░░ 78.3% │ │
│ │ 消費: 21.7% | 残り: 7,830 requests │ │
│ │ 現在のバーンレート: 0.8x (正常) │ │
│ │ 枯渇予測: なし(現在のレートでは枯渇しない) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ SLI Trend (30 days) │ │
│ │ 99.99% ─┐ │ │
│ │ 99.95% ─┤─── SLO Target ────────────────── │ │
│ │ 99.90% ─┤ ╱╲ ╱╲ │ │
│ │ 99.85% ─┤ ╱ ╲╱╱ ╲ ╱╲ │ │
│ │ 99.80% ─┤───╱────────────╱──╲─────────── │ │
│ │ └────────────────────────────────── │ │
│ │ Day 1 Day 15 Day 30 │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Recent Incidents │ │
│ │ • 2024-01-10: DB failover (15min, 0.02% budget) │
│ │ • 2024-01-05: Deploy rollback (5min, 0.01%) │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
第6章: SLOの高度なパターン
6.1 依存サービスのSLO
直列依存(Sequential Dependencies):
ServiceA → ServiceB → ServiceC
合成SLO = SLO_A × SLO_B × SLO_C
例: 99.9% × 99.9% × 99.9% = 99.7%
→ 依存が増えるほど、全体のSLOは低下する
→ 各サービスのSLOはエンドツーエンドSLOより高く設定する必要がある
並列依存(Parallel Dependencies with redundancy):
ServiceA → ServiceB (primary)
→ ServiceC (fallback)
両方が同時に失敗する確率:
= (1 - SLO_B) × (1 - SLO_C)
= 0.001 × 0.001 = 0.000001 = 99.9999%
6.2 ユーザージャーニーベースのSLO
# 単一エンドポイントではなく、ユーザージャーニー全体でSLOを定義
user_journey: "商品購入フロー"
steps:
- name: "商品検索"
slo: { availability: 99.9%, latency_p95: 500ms }
- name: "商品詳細表示"
slo: { availability: 99.9%, latency_p95: 300ms }
- name: "カートに追加"
slo: { availability: 99.95%, latency_p95: 200ms }
- name: "決済処理"
slo: { availability: 99.99%, latency_p95: 2000ms }
# 重要度に応じてSLOの厳しさを変える
# 決済 > カート > 検索 の順に厳しく
6.3 段階的SLOの導入
Month 1-2: 観測フェーズ
- SLIの計測を開始(SLOは設定しない)
- ベースラインデータを収集
- チームにSLI/SLOの概念を教育
Month 3-4: 初期SLOフェーズ
- ベースラインデータに基づいてSLOを設定
- ダッシュボードの構築
- アラートの初期設定(情報アラートのみ)
Month 5-6: 運用フェーズ
- エラーバジェットポリシーの導入
- バーンレートアラートの有効化
- ポストモーテムとSLOの連携
Month 7+: 最適化フェーズ
- SLOの見直しと調整
- 他サービスへの展開
- SLOベースの意思決定の定着
まとめ
SLOはサービスの信頼性を定量的に管理するための不可欠なフレームワークである:
- SLI設計: ユーザー視点で可用性/レイテンシ/品質/スループットを計測
- SLO設定: 達成可能で意味のある目標を3-5個に絞って定義
- エラーバジェット: イノベーションと信頼性のバランスを定量管理
- バーンレートアラート: マルチウィンドウ方式で誤報を最小化
- ダッシュボード: リアルタイムのSLO達成状況とエラーバジェット残量
- ツールチェーン: OpenSLO、Sloth、Prometheus、Grafana
- 文書化: SLOドキュメントによるステークホルダー間の合意
- 段階的導入: 観測→初期SLO→運用→最適化のフェーズ
参考文献
- "The Art of SLOs" — https://sre.google/resources/practices-and-processes/art-of-slos/
- "Implementing Service Level Objectives" - Alex Hidalgo (O'Reilly)
- "Site Reliability Engineering" Chapter 4: Service Level Objectives — https://sre.google/sre-book/service-level-objectives/
- "The Site Reliability Workbook" Chapter 2: Implementing SLOs — https://sre.google/workbook/implementing-slos/
- OpenSLO Specification: https://openslo.com/
- Sloth: https://sloth.dev/
- Google Cloud SLO: https://cloud.google.com/stackdriver/docs/solutions/slo-monitoring
- "SLO Burn Rate Alerts" by Google: https://sre.google/workbook/alerting-on-slos/