Chuyển đến nội dung chính

レッスン 15: メトリクス — プロメテウスとグラファナ

RED メソッド、USE メソッド、Prometheus アーキテクチャ、基本的な PromQL、Kubernetes の ServiceMonitor、Grafana ダッシュボード設計、アラート ルール、および Alertmanager 構成。

🏗️ アーキテクチャ — レッスン 15 レッスン 15: メトリクス — プロメテウスとグラファナ

クラウドネイティブのマイクロサービスアーキテクチャ

パート 5: 可観測性 — 3 つの柱

xdev.asia

レッスン 15: メトリクス — プロメテウスとグラファナ

はじめに

マイクロサービス システムでは、従来のデバッグのように実行中のサービスを「内部を見る」ことはできません。 Metrics は Observability の最初のプラットフォームであり、システムの健全性とパフォーマンスを長期にわたって測定する数値データを提供します。

Prometheus + Grafana は、メトリクスの収集と視覚化のためのクラウド ネイティブ エコシステムの事実上の標準デュオです。


1. 測定方法

1.1 RED メソッド — サービスの場合

Tom Wilkie による RED メソッド は、各サービスの 3 つの最も重要な指標に焦点を当てています。

R — Rate     : Số lượng request service xử lý mỗi giây
E — Errors   : Tỷ lệ phần trăm request thất bại
D — Duration : Thời gian phân phối (latency percentiles)

Order Service のダッシュボードの例:

┌─────────────────────────────────────────────────────────┐
│                  Order Service — RED                    │
├──────────────────┬──────────────────┬───────────────────┤
│ Rate             │ Error Rate       │ Duration (p99)    │
│ 1,247 req/s      │ 0.3%             │ 145ms             │
│ ↑ +12% vs 1h ago│ ↓ Normal         │ → Within SLO      │
└──────────────────┴──────────────────┴───────────────────┘

1.2 USE メソッド — リソースの場合

インフラストラクチャ リソースに対する Brendan Gregg による USE メソッド:

U — Utilization : Tỷ lệ thời gian resource đang busy (%)
S — Saturation  : Mức độ "hàng đợi" extra work (queue length)
E — Errors      : Số lượng lỗi từ resource

各リソースに適用します。

リソース活用彩度エラー
CPUrate(cpu_seconds[5m])負荷平均 > コアマシンチェックエラー
メモリ1 - mem_free/mem_totalスワップレート、OOM キル
ディスク I/Orate(disk_io_time[5m])ディスクキューの長さI/O エラー
ネットワークrate(net_bytes[5m]) / capacityパケットのドロップ/再送信NIC エラー

1.3 ゴールデン シグナル — エンドツーエンドの場合

Google SRE は 4 つのゴールデン シグナル を定義しています。

  1. レイテンシ — リクエストの処理時間 (成功とエラーのレイテンシを区別)
  2. トラフィック — システムの需要 (リクエスト/秒、同時ユーザー数)
  3. エラー — リクエスト失敗率 (明示的な 5xx、暗黙的な間違ったデータ)
  4. 飽和 — システム リソースの充満レベル

2. プロメテウスのアーキテクチャ

2.1 概要

┌─────────────────────────────────────────────────────────────┐
│                      Prometheus Server                      │
│                                                             │
│  ┌──────────────┐   ┌──────────────┐   ┌────────────────┐  │
│  │ Retrieval    │   │ TSDB         │   │ HTTP Server    │  │
│  │ (Scraper)    │   │ (Time-Series │   │ (Query/API)    │  │
│  │              │   │  Database)   │   │                │  │
│  └──────┬───────┘   └──────────────┘   └────────┬───────┘  │
│         │                                        │          │
└─────────┼────────────────────────────────────────┼──────────┘
          │ /metrics scrape                        │ PromQL
          ▼                                        ▼
 ┌──────────────────┐                    ┌─────────────────┐
 │ Targets:         │                    │   Grafana       │
 │ - App /metrics   │                    │   Alertmanager  │
 │ - Node Exporter  │                    │   Other clients │
 │ - cAdvisor       │                    └─────────────────┘
 │ - kube-state-mts │
 └──────────────────┘

プルベースのモデル: Prometheus は、15 ~ 30 秒ごとにターゲットからメトリクスを積極的に取得します。プッシュベース (InfluxDB、StatsD) とは異なります。

2.2 メトリクスの種類

# Counter — Chỉ tăng, dùng cho counts và rates
http_requests_total{method="POST", status="200"} 1027

# Gauge — Tăng giảm tự do, dùng cho current values
memory_usage_bytes 153344000
active_connections 42

# Histogram — Phân phối latency, tạo buckets tự động
http_request_duration_seconds_bucket{le="0.1"} 8521
http_request_duration_seconds_bucket{le="0.5"} 9812
http_request_duration_seconds_sum 1234.6789
http_request_duration_seconds_count 9987

# Summary — Như Histogram nhưng tính percentile phía client
http_request_duration_seconds{quantile="0.99"} 0.145

2.3 説明形式

各サービスは次の場所でメトリクスを公開します。 /metrics エンドポイント:

// Spring Boot — thêm dependency
// actuator + micrometer-registry-prometheus

// Sau đó endpoint tự động có:
// GET /actuator/prometheus
// Go — prometheus/client_golang
import "github.com/prometheus/client_golang/prometheus"
import "github.com/prometheus/client_golang/prometheus/promauto"

var (
    httpRequestsTotal = promauto.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total HTTP requests",
        },
        []string{"method", "path", "status"},
    )

    httpDuration = promauto.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "path"},
    )
)

3. Kubernetes の統合

3.1 kube-プロメテウス-スタック

最も簡単な方法: キットをインストールする kube-prometheus-stack Helm チャート — Prometheus、Grafana、Alertmanager、および必要なエクスポーターが含まれます。

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

helm upgrade --install kube-prometheus-stack \
  prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.adminPassword=<your-password> \
  --set prometheus.prometheusSpec.retention=15d

3.2 サービスモニター

ServiceMonitor Prometheus Operator の CRD (カスタム リソース定義) です。サービスからメトリクスを取得する方法を定義します。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: order-service
  namespace: services-prod
  labels:
    # Phải match với selector của Prometheus
    release: kube-prometheus-stack
spec:
  namespaceSelector:
    matchNames:
      - services-prod
  selector:
    matchLabels:
      app: order-service
  endpoints:
    - port: http
      path: /actuator/prometheus
      interval: 15s
      scrapeTimeout: 10s

3.3 ポッドモニター

サービスに Kubernetes Service がない場合 (直接 Pod のみがある場合):

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: worker-pods
spec:
  selector:
    matchLabels:
      app: async-worker
  podMetricsEndpoints:
    - port: metrics
      path: /metrics
      interval: 30s

4. PromQL — Prometheus クエリ言語

4.1 基本構文

# Instant vector — giá trị tại thời điểm hiện tại
http_requests_total

# Range vector — giá trị trong khoảng thời gian
http_requests_total[5m]

# Filtering bằng labels
http_requests_total{job="order-service", status=~"5.."}

# Operators
http_requests_total{status=~"5.."} / http_requests_total  # ratio

4.2 重要な機能

# rate() — tốc độ thay đổi per second (dùng cho Counter)
rate(http_requests_total[5m])

# irate() — instant rate (nhạy hơn với spike ngắn)
irate(http_requests_total[5m])

# increase() — tổng tăng trong khoảng thời gian
increase(http_requests_total[1h])

# histogram_quantile() — percentile từ Histogram
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# sum() với by/without
sum(rate(http_requests_total[5m])) by (service)

# topk()
topk(5, rate(http_requests_total[5m]))

4.3 実際のクエリ

# Error rate (5xx) cho tất cả services
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)

# p99 latency theo service
histogram_quantile(
  0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
)

# CPU usage trên các pods
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace)

# Memory usage (bytes)
sum(container_memory_rss{container!=""}) by (pod, namespace)

# Pod restart count
kube_pod_container_status_restarts_total{namespace="services-prod"}

# Service availability (based on successful requests)
1 - (
  sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
  /
  sum(rate(http_requests_total[5m])) by (service)
)

5. Grafana ダッシュボード

5.1 優れたダッシュボード構造

ダッシュボードの設計原則:

Level 1 — Overview (Top Row)
  Tổng quan toàn bộ hệ thống:
  - Total request rate
  - Overall error rate
  - System availability
  - Active alerts count

Level 2 — Service Overview
  Metrics per service:
  - Rate, Errors, Duration (RED)
  - Service status

Level 3 — Drill-down
  Chi tiết khi có vấn đề:
  - Request breakdown by endpoint
  - Latency percentiles (p50, p95, p99)
  - Error messages
  - Dependencies

5.2 コードとしてのダッシュボード

ダッシュボードを JSON として Git に保存します。

# Grafana ConfigMap trong Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-service-dashboard
  namespace: monitoring
  labels:
    grafana_dashboard: "1"  # Auto-discovered bởi Grafana sidecar
data:
  order-service.json: |
    {
      "title": "Order Service",
      "uid": "order-service",
      "panels": [ ... ]
    }

6. アラート

6.1 プロメテウスルール

アラート ルールの定義:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: order-service-alerts
  namespace: services-prod
  labels:
    release: kube-prometheus-stack
spec:
  groups:
    - name: order-service.rules
      interval: 30s
      rules:
        # Error rate cao
        - alert: HighErrorRate
          expr: |
            sum(rate(http_requests_total{service="order-service", status=~"5.."}[5m]))
            /
            sum(rate(http_requests_total{service="order-service"}[5m]))
            > 0.05
          for: 2m
          labels:
            severity: critical
            team: backend
          annotations:
            summary: "High error rate on order-service"
            description: "Error rate {{ $value | humanizePercentage }} > 5%"

        # Latency cao
        - alert: HighLatency
          expr: |
            histogram_quantile(0.99,
              sum(rate(http_request_duration_seconds_bucket{service="order-service"}[5m]))
              by (le)
            ) > 1.0
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "High p99 latency on order-service"
            description: "p99 latency is {{ $value | humanizeDuration }}"

        # Pod down
        - alert: PodDown
          expr: |
            kube_deployment_status_replicas_available{
              namespace="services-prod",
              deployment="order-service"
            } < kube_deployment_spec_replicas{
              namespace="services-prod",
              deployment="order-service"
            }
          for: 1m
          labels:
            severity: critical
          annotations:
            summary: "Order service pod(s) down"

6.2 アラートマネージャー

Alertmanager は Prometheus からアラートを受信し、通知を送信します。

# alertmanager.yaml
global:
  slack_api_url: 'https://hooks.slack.com/services/...'

route:
  group_by: ['alertname', 'service']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 1h
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty-critical'
      continue: true
    - match:
        severity: warning
      receiver: 'slack-warnings'

receivers:
  - name: 'default'
    slack_configs:
      - channel: '#alerts'
        text: '{{ .CommonAnnotations.summary }}'

  - name: 'pagerduty-critical'
    pagerduty_configs:
      - service_key: '<key>'

  - name: 'slack-warnings'
    slack_configs:
      - channel: '#alerts-warning'
        send_resolved: true

7. SLI / SLO / SLA

指標を サービス レベル目標と組み合わせる:

# SLO Definition
service: order-service
slo:
  # 99.9% requests thành công trong 30 ngày
  - name: availability
    target: 99.9%
    indicator:
      ratio:
        good_events: http_requests_total{status!~"5.."}
        total_events: http_requests_total

  # 95% requests hoàn thành trong 200ms
  - name: latency
    target: 95%
    indicator:
      ratio:
        good_events: http_request_duration_seconds_bucket{le="0.2"}
        total_events: http_request_duration_seconds_count

エラーバジェット:

  • SLO 99.9% → エラー バジェット = 0.1% = 43.8 分/月
  • エラー バジェットがなくなったら、機能の導入を凍結し、信頼性を重視します

8. ベストプラクティス

メトリクスに正しく名前を付けます:

# Format: <namespace>_<subsystem>_<name>_<unit>
http_request_duration_seconds
database_queries_total
cache_hit_ratio
background_jobs_processed_total

カーディナリティ制御:

# ĐÚNG — cardinality thấp, controllable labels
http_requests_total{method, status_code, service}

# SAI — cardinality explode làm Prometheus OOM
http_requests_total{user_id, request_id, ip_address}

事前計算コストの高いクエリの記録ルール:

groups:
  - name: recording_rules
    rules:
      - record: job:http_requests_total:rate5m
        expr: sum(rate(http_requests_total[5m])) by (job)

概要

コンセプト目的
REDメソッド各サービスの健全性を測定する
USEメソッドインフラストラクチャ リソースの健全性の測定
サービスモニターPrometheus と Kubernetes の統合
プロムQLメトリクスのクエリと計算
プロメテウスルールアラート ルールの定義
アラートマネージャー通知のルーティングと送信
SLO/SLI信頼性目標の定量化

次の記事: ロギング — 構造化ロギング、Loki および ELK スタック