SLO設計で2年間失敗し続けた僕が、ようやく運用が回り始めた話
「SLOは作ったのに誰も見てない」「バジェットが枯渇して初めて気づいた」そんな経験ありませんか?2年間の失敗から学んだ現実的な運用パターンを共有します。
SLI/SLOを「ちゃんと設計した」気になっていた時期があった。ドキュメントも整えた、ダッシュボードも作った。でも半年後にインシデントが起きて振り返ってみると、設定していた SLO が全員に無視されていた。というか、SLO が何を意味するか理解されていなかった。
その苦い経験から2年、今のチームではだいぶ整ってきたので、失敗談も含めて書き残しておこうと思う。「SLI/SLO の概念自体を基礎から学びたい」というよりは、「概念は知ってるけど実際の運用が難しい」という人に向けて書く。
なぜ最初の SLO 設計は死んだか
最初の失敗を振り返ると、大きく3つの問題があった。
1つ目は「技術者だけで閉じた SLO」だったこと。 HTTP 5xx エラー率 < 0.1% みたいなやつ。この数字、ユーザーにとって何を意味するか説明できますか? 当時の僕には正直できなかった。エラー率が 0.09% でも、ユーザーが使う決済フローでだけエラーが集中していたら意味がない。
2つ目はアラートと SLO の乖離。 SLO を設定したのに、アラートは別で管理されていた。SLO バジェットが枯渇しかけていても誰も気づかず、突然大障害になって初めて「あ、バジェットなかったのか」となった。
3つ目は SLO の数が多すぎた。 最初の設計で 20 個以上の SLI を定義した。運用しているうちに更新されなくなって、形骸化した。
インシデント対応の最新ベストプラクティス2026でも触れているけど、インシデントが起きてから SLO の大切さに気づくのはあるあるなんですよね。そうなる前に設計を見直しておきたい。
2026年の SLI 設計:ユーザージャーニーから逆算する
今は 「ユーザーが何をしたいか」から SLI を決める ようにしている。Google の SRE ワークブックにも書いてあることだけど、実際にやると思ったより難しい。
具体的には、まずサービスのクリティカルユーザージャーニー(CUJ)を3〜5個書き出す。うちのプロダクト(BtoB SaaS)だとこんな感じ。
CUJ 1: ユーザーがログインしてダッシュボードを開ける
CUJ 2: データをアップロードして処理が完了する
CUJ 3: レポートを生成してダウンロードできる
CUJ 4: API 経由で外部システムからデータを取得できる
これを見ながら、各 CUJ に対応する SLI を決める。
# SLO 定義ファイル(社内 YAML 管理)
slо_definitions:
- name: "login_and_dashboard_availability"
cuj: "ユーザーがログインしてダッシュボードを開ける"
sli:
type: request_based
good_events: "HTTP 2xx レスポンス かつ レスポンスタイム < 2000ms"
total_events: "全リクエスト"
measurement_window: "28日間ローリング"
slo_target: 99.5
error_budget_alert_threshold: 50 # バジェット 50% 消化でアラート
- name: "data_upload_processing"
cuj: "データをアップロードして処理が完了する"
sli:
type: window_based
good_window: "ジョブ投入から 5 分以内に完了"
total_windows: "全ジョブ実行"
slo_target: 99.0
error_budget_alert_threshold: 30
この形式で管理することで、SLO がなぜ存在するかが誰にでもわかる。プロダクトマネージャーとの会話でも「この SLO はログインの体験を守るためです」と説明できる。
SLI の種類を使い分ける
地味に大事なのが SLI タイプの選択で、適当に選ぶと後で計算が壊れる。
| SLI タイプ | 適用場面 | 注意点 |
|---|---|---|
| Request-based | API・Web レスポンス | サンプリングに注意 |
| Window-based | バッチ処理・非同期 | ウィンドウ定義が難しい |
| Uptime-based | 基盤インフラの疎通確認 | 精度が粗い、補助指標向き |
| User-based | プレミアム顧客向け加重 | 実装コスト高め |
正直、Window-based SLI はまだ設計に迷うことが多い。バッチ処理のジョブが「完了」したとみなす定義が曖昧だと、SLO の計算がおかしくなる。ここは好み分かれるかも。
コンポジット SLO の実装:複数サービスをまとめて見る
2026年時点でうちのチームが一番効果を感じているのがコンポジット SLO だ。マイクロサービス構成だと、個別の SLO が全部グリーンなのにユーザー体験が悪いという状況が起きる。
例えばこういう依存関係があるとする。
flowchart TB
User([ユーザー])
FE[フロントエンド\nSLO: 99.9%]
API[API Gateway\nSLO: 99.9%]
Auth[認証サービス\nSLO: 99.95%]
Data[データサービス\nSLO: 99.5%]
DB[(PostgreSQL)]
User --> FE
FE --> API
API --> Auth
API --> Data
Data --> DB
subgraph composite ["コンポジット SLO 対象"]
FE
API
Auth
Data
end
各サービスが SLO を達成しても、直列依存の場合は掛け算になる。0.999 × 0.999 × 0.9995 × 0.995 ≈ 0.993。つまりユーザー体験の実効可用性は 99.3% 程度になる。これをコンポジット SLO として別途定義する。
# コンポジット SLO 計算スクリプト
from dataclasses import dataclass
from typing import List
import math
@dataclass
class ServiceSLO:
name: str
target: float # 0.999 のような小数
dependency_type: str # 'serial' or 'parallel'
def calculate_composite_slo(
services: List[ServiceSLO],
journey_name: str
) -> float:
"""
ユーザージャーニー全体のコンポジット SLO を計算
直列依存は積、並列依存は補集合の積の補集合
"""
serial_services = [s for s in services if s.dependency_type == 'serial']
parallel_groups = [s for s in services if s.dependency_type == 'parallel']
# 直列依存の計算
serial_availability = math.prod([s.target for s in serial_services])
# 並列依存の計算(冗長化されているケース)
if parallel_groups:
parallel_unavailability = math.prod([1 - s.target for s in parallel_groups])
parallel_availability = 1 - parallel_unavailability
composite = serial_availability * parallel_availability
else:
composite = serial_availability
print(f"Journey: {journey_name}")
print(f" 各サービス SLO: {[f'{s.name}={s.target*100:.3f}%' for s in services]}")
print(f" コンポジット SLO: {composite * 100:.3f}%")
print(f" 月間許容ダウンタイム: {(1-composite)*30*24*60:.1f} 分")
return composite
# 実際に計算してみる
services = [
ServiceSLO("frontend", 0.999, "serial"),
ServiceSLO("api_gateway", 0.999, "serial"),
ServiceSLO("auth_service", 0.9995, "serial"),
ServiceSLO("data_service", 0.995, "serial"),
]
result = calculate_composite_slo(services, "ダッシュボード表示")
実行すると:
Journey: ダッシュボード表示
各サービス SLO: ['frontend=99.900%', 'api_gateway=99.900%', 'auth_service=99.950%', 'data_service=99.500%']
コンポジット SLO: 99.254%
月間許容ダウンタイム: 53.7 分
この結果をプロダクトチームに見せると「え、各サービスは 99.9% なのに全体は 99.2%?」という反応になる。そこから「じゃあ data_service の SLO を引き上げましょう」という具体的な議論になる。数字があると会話が変わるんですよね、本当に。
Prometheus + Sloth でエラーバジェットを実装する
概念の話だけだとふわっとするので、実際の実装を見ていく。2026年時点でうちが使っているのは Sloth(SLO Generator)で、YAML で SLO を定義すると Prometheus ルールを自動生成してくれる。
# sloth-slo.yaml
version: "prometheus/v1"
service: "api-gateway"
labels:
team: "platform"
env: "production"
slos:
- name: "requests-availability"
objective: 99.9
description: "API ゲートウェイの可用性 SLO"
sli:
events:
error_query: |
sum(rate(http_requests_total{
job="api-gateway",
code=~"5.."
}[{{.window}}]))
total_query: |
sum(rate(http_requests_total{
job="api-gateway"
}[{{.window}}]))
alerting:
name: "ApiGatewayAvailability"
page_alert:
labels:
severity: critical
channel: pagerduty
ticket_alert:
labels:
severity: warning
channel: slack
Sloth でビルドすると Prometheus の recording rules と alerting rules が生成される。
$ sloth generate -i sloth-slo.yaml -o prometheus-rules.yaml
# 生成されたルールの確認
$ cat prometheus-rules.yaml | grep 'record:' | head -10
record: slo:sli_error:ratio_rate5m
record: slo:sli_error:ratio_rate30m
record: slo:sli_error:ratio_rate1h
record: slo:sli_error:ratio_rate6h
record: slo:sli_error:ratio_rate1d
record: slo:sli_error:ratio_rate3d
record: slo:error_budget:ratio
record: slo:time_period:days
...
このルールを Grafana でダッシュボード化するとこういう構成になる。
flowchart LR
subgraph datasource ["データソース"]
App[アプリケーション]
Infra[インフラ]
end
subgraph collection ["収集・集計"]
Prom[Prometheus]
Sloth[Sloth SLO Generator]
end
subgraph visualization ["可視化・通知"]
Grafana[Grafana Dashboard]
AM[AlertManager]
PD[PagerDuty]
Slack[Slack]
end
App -->|metrics| Prom
Infra -->|metrics| Prom
Sloth -->|recording rules| Prom
Prom -->|SLO metrics| Grafana
Prom -->|alerts| AM
AM --> PD
AM --> Slack
Grafana SLO プラグイン(2025年末にリリースされた新版)も試してみたけど、正直 Sloth + カスタムダッシュボードの方が細かく制御できる。現状はそっちを使い続けている。ここはまだ検証中で、組織によって向き不向きがあると思う。
エラーバジェット消化率の可視化
月次でこういうグラフを出している。
xychart-beta
title "エラーバジェット消化率 月次推移(%)"
x-axis ["1月", "2月", "3月", "4月", "5月"]
y-axis "消化率 (%)" 0 --> 120
line [23, 45, 18, 102, 61]
bar [23, 45, 18, 102, 61]
4月に 100% 超えているのは実際にインシデントがあった月だ。こういうグラフを見せると「4月は何があったか」という会話が生まれる。インシデント対応の最新ベストプラクティス2026で書いたポストモーテムと組み合わせて使うと、再発防止の議論がしやすくなる。
運用して2年でわかった、SLO 設計の現実的なコツ
SLO の数は「5個以内」に絞る
最初の失敗で書いたとおり、20個の SLO は死ぬ。今は CUJ ベースで5個以内に絞っている。迷ったら「この SLO が赤くなったとき、具体的に誰が何をするか言えるか?」を問いにする。言えないなら削除候補。これ、シンプルだけど地味に効く基準だと思う。
エラーバジェットポリシーを先に決める
「バジェットが 50% 消化したら機能開発を止めて信頼性改善に集中する」というポリシーを、マネージャーと事前合意しておく。これがないと、バジェット枯渇しても「今スプリント中だから…」で誰も動かない。
うちのチームのポリシーはこんな感じ。
| 消化率 | アクション |
|---|---|
| 50% 未満 | 通常開発継続 |
| 50〜75% | 信頼性改善タスクを次スプリントに入れる |
| 75〜100% | 機能開発と信頼性改善を 50:50 にする |
| 100% 超過 | 機能リリースを一時停止、信頼性改善に全集中 |
これを JIRA のダッシュボードウィジェットに組み込んで、毎朝スタンドアップで全員が見られるようにしている。
SLO はサービスオーナーと一緒に決める
これが一番大事かもしれない。SRE チームだけで SLO を決めると「押しつけ感」が出て誰も守らなくなる。ワークショップ形式で「ユーザーが怒るのはどんな状況?」から逆算して、サービスオーナーと一緒に数値を決める。最初は合意形成が面倒だけど、後の運用が全然違う。
皆さんのチームでは、SLO の設定はどうやって合意取ってますか? うちはまだ完璧ではなくて、四半期ごとの SLO レビューで「この数値おかしくない?」という議論が毎回出る。正直もっとうまい方法がある気がしていて、まだ模索中。
SLO と SLA の使い分けを明確に
外部顧客向けの SLA(例:月次 99.9% の可用性を契約で保証)と、内部の SLO(例:99.95% を目標として運用する)を分けて管理する。SLO は SLA より高い目標にして、SLA 違反の前にアクションできる余裕を作る。
| 指標 | 値 | 用途 |
|---|---|---|
| SLA(顧客契約) | 99.9% | 外部契約の保証ライン |
| SLO(内部目標) | 99.95% | バッファ 0.05% を確保 |
| SLI(実測値) | リアルタイム計測 | 実際の観測値 |
このバッファがないと、SLO 違反 = SLA 違反になってしまって心臓に悪い。CloudWatch vs Datadog 2026でも比較したけど、SLO トラッキングの機能は Datadog の方が圧倒的に充実していて、コストと相談しながら使い分けるのが現実解だと思う。
SLO 達成率とビジネス指標の相関を取る
2026年のトレンドとして「SLO とビジネス KPI を紐付ける」という動きが強くなっている。SLO を達成できているとチャーン率が下がる、という相関を示せると、経営層への説得力が全然違う。
xychart-beta
title "SLO 達成率 vs チャーン率 の相関(四半期別)"
x-axis ["Q1 2025", "Q2 2025", "Q3 2025", "Q4 2025", "Q1 2026"]
y-axis "SLO 達成率 (%)" 95 --> 100
line [96.2, 98.1, 99.3, 97.8, 99.5]
このデータはあくまで例だけど、うちのプロダクトでも似たような相関が取れてきた。「信頼性への投資はビジネス価値がある」という議論を数字でできるようになると、SRE チームのプレゼンスが上がる。
ただ相関と因果は別なので、過信は禁物。SLO 改善しか要因がないわけじゃないし、「SLO 達成率を上げれば必ずチャーン減る」と言い切るのは危険。あくまで傾向として持っておく程度が現実的だと思う。
まとめ
SLI/SLO 設計で2年間失敗して学んだことをまとめる。
- CUJ から逆算して SLI を定義する。技術指標ではなくユーザー体験を守るための数値として設計する。SLO は5個以内に絞ること
- コンポジット SLO で全体像を把握する。個別サービスの SLO が全部グリーンでも、直列依存では実効可用性が落ちる。計算して見せると認識が変わる
- Sloth + Prometheus で SLO を自動計算する。手動管理は死ぬ。ツールで自動化して、人間はポリシーと会話に集中する
- エラーバジェットポリシーを事前に合意する。数値だけ決めても動かない。「バジェット X% 消化したら何をするか」まで決めてから運用開始する
- SLO はサービスオーナーと一緒に決める。SRE が一方的に設定した SLO は形骸化する。ワークショップで合意形成することが長期的に効く
次のアクション: まずサービスのクリティカルユーザージャーニーを3個書き出してみてほしい。それだけで SLI 設計の議論が始められる。完璧な設計を最初から目指すより「動かしながら改善する」姿勢の方が、SLO は長続きする。
カオスエンジニアリング2026と組み合わせると、SLO がどれだけ実際のカオス試験に耐えられるかを検証できるので、次のステップとして試してみる価値があると思う。