LESSON 30分

ストーリー

高橋アーキテクト
メトリクスの種類はわかった。次は、それをどうやって収集・保存するかだ

高橋アーキテクトがPrometheusのダッシュボードを見せた。

高橋アーキテクト
Prometheusは、CNCFが支援するメトリクス収集のデファクトスタンダードだ。Pull型のアーキテクチャとPromQLというクエリ言語が特徴だよ

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 }}"

まとめ

ポイント内容
PrometheusPull型のメトリクス収集ツール(CNCFデファクトスタンダード)
/metricsアプリが公開するメトリクスエンドポイント
PromQL強力なクエリ言語(rate, histogram_quantile等)
アラートルールPromQL式 + 閾値 + 持続時間で定義

チェックリスト

  • PrometheusのPull型アーキテクチャを説明できる
  • Node.jsアプリでメトリクスを公開する実装ができる
  • 基本的なPromQLクエリを書ける
  • アラートルールの定義方法を理解した

次のステップへ

次は「Grafanaによる可視化」を学びます。Prometheusで収集したメトリクスを効果的に可視化する方法を見ていきましょう。


推定読了時間: 30分