404 Not Found

404 Not Found


nginx

モニタリング — Prometheus + Grafana フルスタックオブザーバビリティ

モニタリングは自動車のダッシュボードのようなもの - 速度計 (QPS), 油温 (レイテンシ), エンジン警告灯 (エラー率)が, 車 (システム)の健康状態を常に知らせてくれます。ダッシュボードがなければ, エンジンから煙が出るまで異常に気づかないでしょう。

1. 学ぶ内容


2. Aliceの実話

(1) 悩み:問題が起きてから気づく

午前3時, PriceTrackerのデータベースコネクションプールが枯渇し, APIが500エラーを返し始めました。Aliceが気づいたのは午前8時, ユーザーからの苦情が届いてからでした。リアルタイムモニタリングがないため, Charlieは事後にログを確認するしかなく, コネクションプールが午前5時にはすでにアラートを出していたことを発見しました - モニタリングがあれば, 5分以内に検出して解決できたはずです。

(2) PrometheusとGrafanaによる解決策

Prometheusは毎秒メトリック (リクエスト数, レイテンシ, エラー率)を収集し, Grafanaがリアルタイムで可視化し, AlertManagerはメトリックが正常範囲を逸脱した際に自動的にアラートを送信します - 「ユーザーの苦情でしか問題を知る」から「5分以内の自動通知」へとプロセスが変わりました。

(3) 成果

P99レイテンシの急増は1分以内にアラートをトリガーし, データベースコネクションプール枯渇前に自動通知が送信され, 問題検出時間が「数時間」から「数分」に短縮され, Charlieはもう24時間連続で画面を見張る必要がなくなりました。


3. Prometheus メトリックの露出

(1) モニタリングアーキテクチャ

100%
flowchart LR
    App[FastAPI App] -->|/metrics| Prom[Prometheus]
    Prom -->|Query| Grafana[Grafana Dashboard]
    Prom -->|Alert| AlertMgr[AlertManager]
    AlertMgr -->|Notify| Slack[Slack / Email]
    Grafana -->|Visualize| Charlie[Charlie DevOps]

(1) ▶ サンプル:prometheus-fastapi-instrumentatorの統合

PYTHON
# インストール:uv add prometheus-fastapi-instrumentator
from fastapi import FastAPI
from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()

# デフォルトメトリックを追加:リクエスト数, 所要時間, サイズ, 例外
Instrumentator().instrument(app).expose(app)

# /metricsエンドポイントがPrometheusメトリックを露出
# 含む:http_requests_total, http_request_duration_secondsなど

出力:

TEXT
# 実行成功

(2) ▶ サンプル:カスタムメトリック

PYTHON
from prometheus_client import Counter, Histogram, Gauge
from fastapi import FastAPI

app = FastAPI()

# カスタムビジネスメトリック
PRICE_UPDATES = Counter(
    "pricetracker_price_updates_total",
    "Total number of price updates",
    ["category", "currency"],
)

REQUEST_LATENCY = Histogram(
    "pricetracker_request_latency_seconds",
    "Request latency in seconds",
    buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
)

ACTIVE_USERS = Gauge(
    "pricetracker_active_users",
    "Number of active users in last 5 minutes",
)

CACHE_HIT_RATE = Gauge(
    "pricetracker_cache_hit_rate",
    "Redis cache hit rate percentage",
)

@app.post("/api/v1/prices")
async def create_price(price: PriceCreate):
    result = await service.create_price(price)
    # カスタムメトリックを記録
    PRICE_UPDATES.labels(category="electronics", currency="USD").inc()
    return result

出力:

TEXT
# 関数定義成功

(2) REDメソッドの主要メトリック

メトリック タイプ 説明 PromQL
Rate Counter リクエストレート (QPS) rate(http_requests_total[5m])
Errors Counter エラー率 rate(http_requests_total{status=~"5.."}[5m])
Duration Histogram レイテンシ分布 histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

4. Grafanaダッシュボード設計

(1) ダッシュボードレイアウト

100%
graph TD
    Title[PriceTracker モニタリングダッシュボード]
    Title --> Row1[Row 1: 概要]
    Row1 --> QPS[QPS - Rate]
    Row1 --> P50[P50 レイテンシ]
    Row1 --> P99[P99 レイテンシ]
    Row1 --> ErrRate[エラー率]
    
    Title --> Row2[Row 2: ビジネス]
    Row2 --> PriceUpd[価格更新数/分]
    Row2 --> ActiveUsers[アクティブユーザー]
    Row2 --> CacheHit[キャッシュヒット率]
    
    Title --> Row3[Row 3: インフラ]
    Row3 --> DBConns[DB接続数]
    Row3 --> RedisConns[Redis接続数]
    Row3 --> CeleryQ[Celeryキューサイズ]

(1) ▶ サンプル:GrafanaダッシュボードJSON設定 (抜粋)

JSON
{
  "dashboard": {
    "title": "PriceTracker Monitoring",
    "panels": [
      {
        "title": "Request Rate (QPS)",
        "type": "timeseries",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total[5m]))",
            "legendFormat": "Total QPS"
          }
        ]
      },
      {
        "title": "P99 Latency",
        "type": "stat",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))",
            "legendFormat": "P99"
          }
        ],
        "thresholds": {
          "steps": [
            { "value": 0, "color": "green" },
            { "value": 0.1, "color": "yellow" },
            { "value": 0.5, "color": "red" }
          ]
        }
      },
      {
        "title": "Cache Hit Rate",
        "type": "gauge",
        "targets": [
          {
            "expr": "pricetracker_cache_hit_rate",
            "legendFormat": "Hit Rate %"
          }
        ]
      }
    ]
  }
}

出力:

JSON
{
  "dashboard": {
    "title": "PriceTracker Monitoring",
    "panels": [
      {
        "title": "Request Rate (QPS)",
        "type": "timeseries",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total[5m]))",
            "legendFormat": "Total QPS"
          }
        ]
      },
      {
        "title": "P99 Latency",
        "type": "stat",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_buck

5. アラートルール

(1) ▶ サンプル:Prometheusアラートルール

YAML
# prometheus/alert_rules.yml
groups:
  - name: pricetracker_alerts
    rules:
      - alert: HighP99Latency
        expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) > 0.5
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "P99レイテンシが500msを超過"
          description: "P99レイテンシは{{ $value }}s, 閾値は0.5s"

      - alert: HighErrorRate
        expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "エラー率が5%を超過"
          description: "エラー率は{{ $value | humanizePercentage }}"

      - alert: LowCacheHitRate
        expr: pricetracker_cache_hit_rate < 60
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "キャッシュヒット率が60%を下回る"
          description: "現在のヒット率は{{ $value }}%"

      - alert: DatabaseConnectionPoolExhausted
        expr: pricetracker_db_connections_in_use / pricetracker_db_connections_max > 0.9
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "データベースコネクションプール使用率が90%を超過"

出力:

TEXT
モニタリング設定を読み込みました
Prometheus targets: 3 active
Grafana dashboard: ready

(2) ▶ サンプル:Docker Composeにモニタリングスタックを追加

YAML
# docker-compose.ymlに追加
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./docker/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./docker/alert_rules.yml:/etc/prometheus/alert_rules.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--alert.rule-files=/etc/prometheus/alert_rules.yml'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana

  alertmanager:
    image: prom/alertmanager:latest
    ports:
      - "9093:9093"
    volumes:
      - ./docker/alertmanager.yml:/etc/alertmanager/alertmanager.yml

出力:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp

(3) ▶ サンプル:prometheus.yml設定

YAML
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "pricetracker-api"
    metrics_path: "/metrics"
    static_configs:
      - targets: ["api:8000"]

rule_files:
  - "alert_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

出力:

TEXT
設定が反映されました。

❓ よくある質問

Q PrometheusとELKの違いは何ですか?
A Prometheusはメトリックモニタリング (数値時系列)用であり, ELKはログ分析 (テキスト検索)用です。両者は補完関係にあり - Prometheusはトレンドの監視とアラート生成に使用し, ELKは詳細なログの確認による問題のトラブルシューティングに使用します。
Q メトリック収集間隔はどのくらいに設定すべきですか?
A デフォルトの15秒が良いバランスです。短い間隔 (5秒)はよりリアルタイムなデータを提供しますがストレージコストが高くなり, 長い間隔 (60秒)はストレージを節約しますが短い変動を見逃す可能性があります。
Q カスタムメトリックが多すぎるとアプリケーションが遅くなりますか?
A 各メトリックにはわずかなCPUオーバーヘッドがあります。カスタムメトリックは100個以下にすることをお勧めします。ラベルのカーディナリティ (異なる値の数)は, メトリック数よりもパフォーマンスへの影響が大きいため, 高カーディナリティのラベル (user_idなど)は避けてください。
Q Grafanaダッシュボードはどう共有しますか?
A JSONファイルとしてエクスポートし, チームがインポートできます。Grafana.comには様々な既製テンプレートが用意されています。
Q アラートが多すぎる場合 (アラート疲れ)はどうしますか?
A 適切な「for」期間を設定し (一時的な変動によるトリガーを回避), アラートを「warning」または「critical」に分類し, 関連するアラートをグループ化し, 通知チャンネルのノイズを減らしてください。
Q Celeryタスクはどうモニタリングしますか?
A Flowerがタスクレベルのモニタリングを提供し, Prometheusメトリックを露出します。主要メトリックには, タスク成功率, キューサイズ, ワーカーのメモリ使用量などがあります。

📖 まとめ


📝 練習問題

  1. 基本問題 (難易度 ⭐):FastAPIにprometheus-fastapi-instrumentatorを追加し, /metricsエンドポイントがデフォルトHTTPメトリック (http_requests_totalなど)を返すことを確認してください。ヒント:Instrumentator().instrument(app).expose(app)
  2. 応用問題 (難易度 ⭐⭐):3つのカスタムメトリック - PRICE_UPDATES (カテゴリ別Counter), REQUEST_LATENCY (パーセンタイルバケット付きHistogram), CACHE_HIT_RATE (Gauge) - を追加し, エンドポイントでメトリック値を記録してください。ヒント:Counter(..., ["category"]) + .labels(category="electronics").inc()
  3. チャレンジ (難易度 ⭐⭐⭐):Docker ComposeにPrometheus, Grafana, AlertManagerを追加し, prometheus.ymlを設定してFastAPIメトリックを収集し, 2つのアラートルール (P99 > 500 ms と エラー率 > 5%)を作成し, ダッシュボードをGrafanaにインポートしてリアルタイムメトリックを確認してください。ヒント:docker/prometheus.yml + alert_rules.yml + Grafanaデータソース設定

---|

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%