<CodeLearn/>
モニタリング レッスン4

メトリクスとダッシュボード

Prometheus、Grafana、Datadogによるメトリクス収集とAPMを学ぼう

カスタムメトリクスとは

メトリクスとは、システムの状態を数値で表した指標です。 CPUやメモリなどのインフラメトリクスに加えて、アプリケーション固有のカスタムメトリクスを定義することで、 ビジネスの健全性も監視できます。

メトリクスの4つのタイプ:

1. Counter(カウンター)
   - 単調増加する値。リセットされない。
   - 例: リクエスト総数、エラー総数、注文総数

2. Gauge(ゲージ)
   - 上下する値。現在の状態を表す。
   - 例: アクティブ接続数、キューの長さ、メモリ使用量

3. Histogram(ヒストグラム)
   - 値の分布を記録。パーセンタイル計算に使う。
   - 例: リクエストレイテンシー、レスポンスサイズ

4. Summary(サマリー)
   - ヒストグラムに似ているが、クライアント側で集計。
   - 例: リクエスト所要時間の中央値/99パーセンタイル

Prometheus の基本

Prometheusは、オープンソースのメトリクス収集・保存・クエリシステムです。 Pull型でメトリクスを収集し、PromQLというクエリ言語で分析できます。

// npm install prom-client

import client from "prom-client";
import express from "express";

const app = express();

// デフォルトメトリクス(CPU、メモリ等)を収集
client.collectDefaultMetrics();

// カスタムメトリクスの定義
const httpRequestsTotal = new client.Counter({
  name: "http_requests_total",
  help: "Total number of HTTP requests",
  labelNames: ["method", "path", "status"],
});

const httpRequestDuration = new client.Histogram({
  name: "http_request_duration_seconds",
  help: "Duration of HTTP requests in seconds",
  labelNames: ["method", "path"],
  buckets: [0.01, 0.05, 0.1, 0.5, 1, 5],
});

const activeConnections = new client.Gauge({
  name: "active_connections",
  help: "Number of active connections",
});

// ミドルウェアでメトリクスを記録
app.use((req, res, next) => {
  activeConnections.inc();
  const end = httpRequestDuration.startTimer({
    method: req.method,
    path: req.route?.path || req.path,
  });

  res.on("finish", () => {
    activeConnections.dec();
    httpRequestsTotal.inc({
      method: req.method,
      path: req.route?.path || req.path,
      status: res.statusCode,
    });
    end();
  });

  next();
});

// Prometheusがスクレイプするエンドポイント
app.get("/metrics", async (req, res) => {
  res.set("Content-Type", client.register.contentType);
  res.end(await client.register.metrics());
});

PromQL クエリの基本

PromQLはPrometheusのクエリ言語です。 メトリクスの集計やフィルタリングに使います。Grafanaのダッシュボードでも使用します。

# 基本的なクエリ

# リクエスト数のレート(1分間あたり)
rate(http_requests_total[5m])

# ステータスコード別のリクエスト数
sum by (status) (rate(http_requests_total[5m]))

# エラー率(4xx + 5xx)
sum(rate(http_requests_total{status=~"[45].."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100

# 99パーセンタイルのレイテンシー
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)

# 平均レスポンスタイム
rate(http_request_duration_seconds_sum[5m])
/ rate(http_request_duration_seconds_count[5m])

# アクティブ接続数
active_connections

Grafana ダッシュボード

Grafanaは、Prometheusなどのデータソースから メトリクスを可視化するダッシュボードツールです。リアルタイムのグラフやアラートを作成できます。

Grafana ダッシュボード設計のベストプラクティス:

1. RED メソッド(サービスレベル)
   - Rate:     リクエスト数/秒
   - Errors:   エラー率
   - Duration: レスポンスタイム

2. USE メソッド(インフラレベル)
   - Utilization: リソース使用率(CPU、メモリ)
   - Saturation:  キュー長、待ち状態
   - Errors:      エラー数

推奨ダッシュボード構成:
┌─────────────────────────────────────┐
│  [概要] リクエスト数 / エラー率 / P99  │
├──────────────┬──────────────────────┤
│ リクエスト数   │ レスポンスタイム      │
│ (時系列グラフ) │ (時系列グラフ)        │
├──────────────┼──────────────────────┤
│ エラー率      │ ステータスコード分布    │
│ (時系列グラフ) │ (円グラフ)            │
├──────────────┴──────────────────────┤
│ CPU / メモリ / ディスク使用率         │
└─────────────────────────────────────┘

Datadog と APM

Datadogは、メトリクス、ログ、トレースを統合管理できる フルスタック監視プラットフォームです。APM(Application Performance Monitoring)では、 リクエスト単位でのパフォーマンス分析が可能です。

// npm install dd-trace

// dd-traceの初期化(アプリのエントリポイントの最初に)
import tracer from "dd-trace";

tracer.init({
  service: "my-api",
  env: process.env.NODE_ENV,
  version: "1.2.3",
  logInjection: true,  // ログにトレースIDを自動注入
});

// カスタムメトリクスの送信
import { StatsD } from "hot-shots";

const statsd = new StatsD({
  host: "localhost",
  port: 8125,
  prefix: "myapp.",
});

// カウンター
statsd.increment("orders.created", 1, { region: "jp" });

// ゲージ
statsd.gauge("queue.length", 42);

// ヒストグラム(レイテンシー計測)
const start = Date.now();
await processOrder(order);
statsd.histogram("order.processing_time", Date.now() - start);

// カスタムスパン(処理の詳細計測)
const span = tracer.startSpan("payment.process");
span.setTag("payment.method", "credit_card");
try {
  await processPayment(order);
  span.setTag("payment.success", true);
} catch (error) {
  span.setTag("error", true);
  span.setTag("error.message", error.message);
  throw error;
} finally {
  span.finish();
}

リクエストレイテンシーの追跡

パフォーマンス監視で最も重要な指標の1つがレイテンシーです。 平均値だけでなく、パーセンタイル(P50、P95、P99)で計測しましょう。

// なぜ平均値だけではダメなのか?
//
// 100リクエスト:
//   98件 → 50ms
//    2件 → 5000ms(タイムアウト寸前)
//   平均 → 149ms(問題なさそうに見える!)
//   P99  → 5000ms(2%のユーザーが5秒待っている!)

// Express ミドルウェアでレイテンシーを計測
import { Histogram } from "prom-client";

const httpDuration = new Histogram({
  name: "http_request_duration_ms",
  help: "HTTP request duration in milliseconds",
  labelNames: ["method", "route", "status_code"],
  buckets: [10, 50, 100, 200, 500, 1000, 2000, 5000],
});

app.use((req, res, next) => {
  const start = process.hrtime.bigint();

  res.on("finish", () => {
    const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
    httpDuration.observe(
      {
        method: req.method,
        route: req.route?.path || "unknown",
        status_code: res.statusCode,
      },
      durationMs
    );
  });

  next();
});

// Grafana/PromQLでの可視化クエリ
// P50: histogram_quantile(0.5, rate(http_request_duration_ms_bucket[5m]))
// P95: histogram_quantile(0.95, rate(http_request_duration_ms_bucket[5m]))
// P99: histogram_quantile(0.99, rate(http_request_duration_ms_bucket[5m]))

まとめ

  • メトリクスには Counter、Gauge、Histogram、Summary の4タイプがある
  • Prometheusでメトリクスを収集し、PromQLで集計・分析する
  • GrafanaでREDメソッド/USEメソッドに基づくダッシュボードを作成する
  • Datadogはメトリクス・ログ・トレースを統合的に管理できる
  • APMでリクエスト単位のパフォーマンスをトレースする
  • レイテンシーは平均値でなくパーセンタイル(P50/P95/P99)で計測する