ストーリー
高橋アーキテクトがPrometheusのダッシュボードを見せた。
Prometheusのアーキテクチャ
┌──────────────────────────────────────────────┐
│ Prometheus Server │
│ │
│ ┌──────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Retrieval │ │ TSDB │ │ HTTP │ │
│ │ (Pull) │ │ (Storage) │ │ Server │ │
│ └─────┬─────┘ └───────────┘ └───────────┘ │
│ │ │
└────────┼──────────────────────────────────────┘
│ Pull (HTTP GET /metrics)
│
┌────┴────────────────────────┐
│ Targets │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │Service A│ │Service B│ │
│ │ :8080 │ │ :8081 │ │
│ │/metrics │ │/metrics │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────┘
Pull型 vs Push型
| 特徴 | Pull型(Prometheus) | Push型(StatsD等) |
|---|---|---|
| 仕組み | Prometheusがターゲットからメトリクスを取りに行く | アプリがメトリクスを送信する |
| サービス発見 | Prometheus側で管理 | アプリ側で送信先を設定 |
| ヘルスチェック | Pullできない = ダウンとして検知 | 送信がない = 判断が難しい |
| ファイアウォール | ターゲットのポートを開ける必要 | Pushゲートウェイ経由で解決 |
メトリクスの公開(Exposition)
// Node.jsアプリケーションでのPrometheusメトリクス公開
import express from 'express';
import { collectDefaultMetrics, Registry, Counter, Histogram } from 'prom-client';
const register = new Registry();
collectDefaultMetrics({ register }); // Node.jsのデフォルトメトリクス
// カスタムメトリクスの定義
const httpRequestsTotal = new Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'path', 'status'],
registers: [register],
});
const httpRequestDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request duration in seconds',
labelNames: ['method', 'path'],
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
registers: [register],
});
// ミドルウェアでメトリクスを記録
function metricsMiddleware(req: express.Request, res: express.Response, next: express.NextFunction) {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestsTotal.inc({ method: req.method, path: req.route?.path || req.path, status: res.statusCode });
httpRequestDuration.observe({ method: req.method, path: req.route?.path || req.path }, duration);
});
next();
}
// /metrics エンドポイント
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
Prometheusの設定
# prometheus.yml
global:
scrape_interval: 15s # デフォルトの収集間隔
evaluation_interval: 15s # ルール評価間隔
scrape_configs:
- job_name: 'api-gateway'
metrics_path: '/metrics'
static_configs:
- targets: ['api-gateway:8080']
- job_name: 'order-service'
static_configs:
- targets: ['order-service:8081']
- job_name: 'payment-service'
static_configs:
- targets: ['payment-service:8082']
# Kubernetesの場合はService Discovery
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
PromQL(Prometheus Query Language)
# 基本クエリ
http_requests_total # 全メトリクス
http_requests_total{method="POST"} # ラベルフィルタ
http_requests_total{status=~"5.."} # 正規表現フィルタ
# Rate: 1秒あたりのリクエスト数(5分間の平均)
rate(http_requests_total[5m])
# エラー率(%)
rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m])
* 100
# レスポンスタイムのP99
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# サービスごとのリクエスト率
sum by (service) (rate(http_requests_total[5m]))
# 直近1時間で最もエラーが多いエンドポイント
topk(5, sum by (path) (increase(http_requests_total{status=~"5.."}[1h])))
アラートルールの定義
# alert_rules.yml
groups:
- name: service_alerts
rules:
- alert: HighErrorRate
expr: |
rate(http_requests_total{status=~"5.."}[5m])
/ rate(http_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.service }}"
description: "Error rate is {{ $value | humanizePercentage }} for {{ $labels.path }}"
- alert: HighLatency
expr: |
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1
for: 10m
labels:
severity: warning
annotations:
summary: "High P99 latency on {{ $labels.service }}"
まとめ
| ポイント | 内容 |
|---|---|
| Prometheus | Pull型のメトリクス収集ツール(CNCFデファクトスタンダード) |
| /metrics | アプリが公開するメトリクスエンドポイント |
| PromQL | 強力なクエリ言語(rate, histogram_quantile等) |
| アラートルール | PromQL式 + 閾値 + 持続時間で定義 |
チェックリスト
- PrometheusのPull型アーキテクチャを説明できる
- Node.jsアプリでメトリクスを公開する実装ができる
- 基本的なPromQLクエリを書ける
- アラートルールの定義方法を理解した
次のステップへ
次は「Grafanaによる可視化」を学びます。Prometheusで収集したメトリクスを効果的に可視化する方法を見ていきましょう。
推定読了時間: 30分