ストーリー
佐
佐藤CTO
SLI/SLO/SLAの設計は完了した。だが、計測できなければ絵に描いた餅だ
佐
佐藤CTO
PrometheusでメトリクスをCollectし、Grafanaで可視化する — それがSREの計測基盤の標準構成だ
佐
佐藤CTO
ダッシュボードは一度作ったら終わりではなく、チームの意思決定を支援する生きたツールにする必要がある
Prometheusメトリクスの設計
メトリクスタイプ
| タイプ | 用途 | SLIへの使い方 | 例 |
|---|
| Counter | 累積値(単調増加) | リクエスト数、エラー数 | http_requests_total |
| Histogram | 分布(バケット) | レイテンシのパーセンタイル | http_request_duration_seconds |
| Gauge | 瞬間値(増減する) | 現在の接続数、キュー長 | node_memory_available_bytes |
| Summary | 分布(クライアント側計算) | レイテンシ(集約不可) | go_gc_duration_seconds |
SLI用メトリクスの実装
import { Registry, Counter, Histogram, collectDefaultMetrics } from 'prom-client';
const register = new Registry();
collectDefaultMetrics({ register });
// SLI: 可用性メトリクス
const httpRequestsTotal = new Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'handler', 'status'] as const,
registers: [register],
});
// SLI: レイテンシメトリクス
const httpRequestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration in seconds',
labelNames: ['method', 'handler'] as const,
// SLO閾値を含むバケット設計
buckets: [0.01, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 2, 5, 10],
registers: [register],
});
// ミドルウェアでの計測
function metricsMiddleware(req: Request, res: Response, next: NextFunction): void {
const start = process.hrtime.bigint();
res.on('finish', () => {
const durationNs = Number(process.hrtime.bigint() - start);
const durationSec = durationNs / 1e9;
const handler = req.route?.path ?? req.path;
const method = req.method;
const status = res.statusCode.toString();
httpRequestsTotal.inc({ method, handler, status });
httpRequestDuration.observe({ method, handler }, durationSec);
});
next();
}
PromQL基礎
# 1. レート計算(Counter用)
# 直近5分間のリクエスト/秒
rate(http_requests_total[5m])
# 2. 合計(ラベルでグループ化)
sum by (handler) (rate(http_requests_total[5m]))
# 3. 可用性SLI
sum(rate(http_requests_total{status!~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 4. パーセンタイル計算(Histogram用)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)
# 5. エラーバジェット消費率(30日ウィンドウ)
1 - (
sum(increase(http_requests_total{status!~"5.."}[30d]))
/
sum(increase(http_requests_total[30d]))
) / 0.001 # SLO 99.9%の場合
# 6. エラーバジェット残量(分単位)
(
(
sum(increase(http_requests_total{status!~"5.."}[30d]))
/
sum(increase(http_requests_total[30d]))
)
- 0.999
) * 30 * 24 * 60
Grafanaダッシュボード設計
SLOダッシュボードの構成
graph TD
subgraph Dashboard["SLO Dashboard - ShopNow API"]
subgraph KPIs["主要KPI"]
Avail["可用性<br/>99.97%<br/>● Green"]
Budget["エラーバジェット<br/>残67%"]
Burn["バーンレート<br/>0.5x"]
end
subgraph Trends["トレンド"]
SLITrend["可用性 SLI トレンド<br/>(30日ローリング)<br/>実績 vs SLO目標(99.9%)"]
BudgetConsume["エラーバジェット消費(累積)<br/>消費: 33% / 残り: 67%"]
end
subgraph Details["詳細"]
LatencyPanel["レイテンシ p50/p99<br/>p50: 45ms<br/>p99: 280ms<br/>SLO: < 300ms"]
ErrorPanel["エラー率 by エンドポイント<br/>/search: 0.02%<br/>/payment: 0.1%"]
end
end
classDef kpi fill:#198754,stroke:#146c43,color:#fff
classDef trend fill:#0d6efd,stroke:#0a58ca,color:#fff
classDef detail fill:#6c757d,stroke:#495057,color:#fff
class Avail,Budget,Burn kpi
class SLITrend,BudgetConsume trend
class LatencyPanel,ErrorPanel detail
Grafanaダッシュボード定義(JSON抜粋)
{
"dashboard": {
"title": "SLO Dashboard - ShopNow API",
"tags": ["slo", "sre"],
"panels": [
{
"title": "現在の可用性(30日ローリング)",
"type": "stat",
"targets": [
{
"expr": "sum(increase(http_requests_total{status!~\"5..\"}[30d])) / sum(increase(http_requests_total[30d])) * 100",
"legendFormat": "可用性"
}
],
"fieldConfig": {
"defaults": {
"thresholds": {
"steps": [
{ "color": "red", "value": 99.0 },
{ "color": "orange", "value": 99.5 },
{ "color": "yellow", "value": 99.9 },
{ "color": "green", "value": 99.95 }
]
},
"unit": "percent"
}
}
},
{
"title": "エラーバジェット消費率",
"type": "gauge",
"targets": [
{
"expr": "(1 - sum(increase(http_requests_total{status!~\"5..\"}[30d])) / sum(increase(http_requests_total[30d]))) / 0.001 * 100"
}
],
"fieldConfig": {
"defaults": {
"min": 0,
"max": 100,
"thresholds": {
"steps": [
{ "color": "green", "value": 0 },
{ "color": "yellow", "value": 50 },
{ "color": "orange", "value": 80 },
{ "color": "red", "value": 100 }
]
}
}
}
}
]
}
}
ダッシュボード設計のベストプラクティス
USE/REDメソッド
| メソッド | 対象 | メトリクス |
|---|
| USE | リソース(CPU, Memory, Disk) | Utilization, Saturation, Errors |
| RED | サービス(API, マイクロサービス) | Rate, Errors, Duration |
# RED メソッド実装例
# Rate: リクエストレート
sum(rate(http_requests_total[5m])) by (handler)
# Errors: エラーレート
sum(rate(http_requests_total{status=~"5.."}[5m])) by (handler)
/
sum(rate(http_requests_total[5m])) by (handler)
# Duration: レイテンシ(p50, p90, p99)
histogram_quantile(0.50,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, handler)
)
histogram_quantile(0.90,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, handler)
)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, handler)
)
ダッシュボードの階層設計
Level 1: エグゼクティブダッシュボード
│ SLO達成状況、エラーバジェット残量
│ 対象: CTO、VPE、ステークホルダー
│
Level 2: サービスダッシュボード
│ 4ゴールデンシグナル、SLIトレンド
│ 対象: チームリード、SRE
│
Level 3: デバッグダッシュボード
エンドポイント別メトリクス、依存サービス状態
対象: オンコールエンジニア
ダッシュボード設計のアンチパターン
| アンチパターン | 問題 | 改善 |
|---|
| 情報過多 | 1画面に50+パネル | 階層化して5〜10パネルに |
| 意味不明なグラフ | コンテキストなしのメトリクス | タイトル、閾値、SLO線を追加 |
| 静的な閾値 | 季節変動を考慮しない | 動的ベースラインを使用 |
| アラートと連携なし | ダッシュボードだけでは不十分 | Alertmanagerと連携 |
| 更新されない | 古いダッシュボードが放置 | 定期的なレビューと棚卸し |
まとめ
| ポイント | 内容 |
|---|
| メトリクスタイプ | Counter(累積)、Histogram(分布)、Gauge(瞬間値) |
| PromQL | rate、sum by、histogram_quantile でSLIを計算 |
| ダッシュボード構成 | 可用性、バジェット消費、レイテンシ、エラー率を1画面に |
| REDメソッド | Rate/Errors/Duration でサービス品質を可視化 |
| 階層設計 | エグゼクティブ→サービス→デバッグの3層構成 |
チェックリスト
次のステップへ
次は「演習:SLI/SLOを設計しよう」です。マイクロサービスプラットフォームに対して、実践的なSLI/SLO設計を行いましょう。
推定読了時間: 40分