Part 5-1. Prometheusの性能チューニング

導入部

Part 5では Prometheus の日常運用フロー、リソース監視、バージョンアップを学びました。このセクションでは、さらに一歩進んで、Prometheus 環境を本格的にスケール・最適化するための実装ガイドを提供します。

メモリ使用量が増加し続ける、ディスク容量が足りなくなった、クエリ応答が遅くなったといった本番環境での課題に直面している方向けです。このセクションを読み終わると、環境規模に応じた最適化戦略を段階的に実装できるようになるでしょう。

メモリ・ディスク最適化ガイド

Prometheus のメモリ使用量とディスク使用量は密接に関連しており、スクレイプするメトリクス数とターゲット数が増えると、双方が増加します。実装レベルでの最適化を見ていきましょう。

メモリ使用量の計算と最適化

Prometheus のメモリ使用量を見積もるには、複雑な計算が必要です。Prometheus 公式ドキュメント(Storage)では、サンプルあたり「1~2 バイト」が基準とされており、実際のメモリ使用量はスクレイプ間隔、リテンション期間、WAL(Write-Ahead Log)のオーバーヘッドに依存します。

簡易的な見積もりとして、以下の環境規模別の目安をお使いください。

環境規模ターゲット数メトリクス数メモリ目安推奨マシン
小規模環境505,0003GB 程度VM(4GB)
中規模環境20030,0008GB 程度サーバー(16GB)
大規模環境500+100,000+32GB 以上専用サーバー(64GB+)

正確なメモリ使用量の見積もりには、実際の環境でメトリクス数を測定し、Prometheus 自身のメトリクス(prometheus_tsdb_memory_chunks など)で確認することをお勧めします。

メモリ使用量を削減するには、不要なメトリクスを取得しないことが最も効果的です。次のセクション「スクレイプ負荷削減方法」で詳しく解説します。

ディスク容量の見積もりと管理

ディスク使用量の計算式は以下の通りです。

推定ディスク使用量(GB)= (1 日あたりスクレイプデータ量) × リテンション期間(日)

実際の最適化では、段階的なディスク削減アプローチが効果的です。以下の図は、リテンション期間短縮による効果を示しています。

実測値を得るために、既存の Prometheus 環境で確認する方法があります。

bash
# Prometheus データディレクトリのサイズを確認
du -sh /path/to/prometheus/data

# 1日ごとのディスク使用量を測定(24時間待機して確認)
du -sh /path/to/prometheus/data/wal
du -sh /path/to/prometheus/data/block*

実装レベルでの最適化ポイントは、以下の通りです。

1. ブロック圧縮の有効化

Prometheus 2.6.0 以降では、古いデータブロックを自動圧縮できます。

bash
prometheus \
  --storage.tsdb.max-block-duration=24h \
  --storage.tsdb.min-block-duration=2h

この設定により、ブロックの圧縮タイミングを制御し、ディスク I/O を最適化します。圧縮により、通常 20~30% のディスク節約が期待できます。

2. リテンション期間の段階的見直し

ビジネス要件に応じて、リテンション期間を設定します。

重要な注意:リテンション設定は prometheus.yml 内では設定できません。必ずコマンドラインフラグまたは systemd・Docker の設定で指定してください。

正しい設定方法:

bash
prometheus \
  --storage.tsdb.retention.time=15d \
  --storage.tsdb.retention.size=100GB

Docker Compose での実装例:

yaml
services:
  prometheus:
    image: prom/prometheus:latest
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=15d'
      - '--storage.tsdb.retention.size=100GB'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus

運用フェーズごとの推奨値:

  • 開発・検証環境:1~3 日
  • 本番環境(標準監視):15~30 日
  • 本番環境(長期分析):60~90 日

ディスク容量が逼迫している場合は、15 日→7 日へ短縮することで、ディスク使用量を約 50% 削減できます。

実装チェックリスト

メモリ・ディスク最適化の実装状況を確認しましょう。

yaml
✓ メトリクス数を把握している(prometheus:tsdb_symbol_table_size_bytes メトリクスで確認)
✓ ターゲット数を把握している(/api/v1/targets で確認)
✓ ブロック圧縮を有効化している(prometheus.yml で max-block-duration を設定)
✓ リテンション期間をビジネス要件に合わせている(15d、30d、90d など)
✓ メモリ使用量を定期的に監視している(Grafana クエリで process_resident_memory_bytes を表示)
✓ ディスク使用量が上限の 80% を超えないよう管理している

スクレイプ負荷削減方法

メトリクス数が増え続ける場合、スクレイプ処理自体を最適化する必要があります。3 つのアプローチを実装例を交えて説明します。

アプローチ 1:metric_relabel_configs によるメトリクスフィルタリング

最も効果的な方法は、Prometheus に到達する前に不要なメトリクスを削除することです。metric_relabel_configs を使用すれば、スクレイプしたメトリクスの中から条件に基づいて削除できます。

実装例:Node Exporter からの不要メトリクス削除

yaml
scrape_configs:
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']
    metric_relabel_configs:
      # sockstat メトリクスを削除(通常は不要)
      - source_labels: [__name__]
        regex: 'node_sockstat.*'
        action: drop
      # テキストメトリクス(info型)を削除(容量削減)
      - source_labels: [__name__]
        regex: 'node_.*_info'
        action: drop
      # systemd ユニット情報を削除
      - source_labels: [__name__]
        regex: 'node_systemd_unit_state'
        action: drop
      # bonding のような特殊 NIC メトリクスを削除
      - source_labels: [__name__]
        regex: 'node_bonding.*'
        action: drop
      # vlan のような特殊 NIC メトリクスを削除
      - source_labels: [__name__]
        regex: 'node_vlan.*'
        action: drop

このフィルタリングで期待できるメトリクス削減率は 30~50% です。実装前後でメトリクス数を比較してみると、効果が実感できます。

効果測定方法

bash
# フィルタリング前後でメトリクス数を確認(概算値)
curl -s  | jq .

注記:このコマンドで得られるメトリクス数は概算値です。正確なメトリクス数を把握するには、Prometheus 管理画面の「Status」→「Targets」を参照するか、prometheus_tsdb_symbol_table_size_bytes メトリクスで確認してください。

アプローチ 2:スクレイプ間隔の最適化

グローバルスクレイプ間隔と、ジョブごとの異なる設定を組み合わせることで、不要な処理を削減します。

yaml
global:
  scrape_interval: 60s        # デフォルト値を 15s から 60s に延長
  evaluation_interval: 60s

scrape_configs:
  # クリティカルなサービスはスクレイプ間隔を短く
  - job_name: 'api-server'
    scrape_interval: 15s
    static_configs:
      - targets: ['api.example.com:9090']
  
  # 標準的なメトリクスは 60s
  - job_name: 'app-metrics'
    scrape_interval: 60s
    static_configs:
      - targets: ['app.example.com:9090']
  
  # 参考情報的なメトリクスは 300s に延長
  - job_name: 'system-info'
    scrape_interval: 300s
    static_configs:
      - targets: ['system.example.com:9090']

スクレイプ間隔を 15s→60s に変更すると、スクレイプ負荷は約 75% 削減されます(データポイント数が 1/4 になるため)。

アプローチ 3:サービスディスカバリーのフィルタリング

Kubernetes 環境では、特定のラベルを持つポッドのみをスクレイプするようフィルタリングできます。

yaml
scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    # monitoring: "true" ラベルを持つポッドのみスクレイプ
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_label_monitoring]
        action: keep
        regex: 'true'
      # prometheus.io/scrape: "false" のポッドは除外
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: drop
        regex: 'false'

このアプローチで、スクレイプ対象を 50~60% に削減することも可能です。

ストレージ効率化チェックリスト

段階的なリテンション戦略を実装することで、ストレージ効率を最大化しましょう。

三層リテンション戦略の実装

レイヤー期間用途ディスク容量設定方法
ホット0~7 日リアルタイム監視、ダッシュボード50GBretention.time=7d
ウォーム8~30 日トレンド分析、原因調査100GBretention.size=150GB で制御
コールド31 日以上長期分析、コンプライアンス外部ストレージS3、GCS へアップロード

実装ステップ

ステップ 1:リテンション期間の決定

bash
# 現在のリテンション設定を確認
prometheus --version  # 2.26以降を推奨

# ディスク使用量から逆算して適切な期間を計算
# 例:1日1GBの増加量の場合
# 50GB ÷ 1GB/日 = 約50日間のリテンション可能

ステップ 2:prometheus.yml での設定

yaml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

ランタイムフラグとしても指定可能:

bash
prometheus \
  --storage.tsdb.retention.time=15d \
  --storage.tsdb.retention.size=100GB

ステップ 3:定期的な監視

bash
# ディスク使用量の定期的な確認スクリプト
#!/bin/bash
DISK_USAGE=$(du -sh /prometheus/data | cut -f1)
DISK_PERCENT=$(df /prometheus/data | awk 'NR==2 {print $5}' | cut -d% -f1)

if [ $DISK_PERCENT -gt 80 ]; then
  echo "WARNING: Disk usage at ${DISK_PERCENT}%"
  # リテンション短縮を検討
fi

クエリ最適化のコツ集

Prometheus のクエリパフォーマンスは、PromQL の書き方とメモリ使用量に大きく影響します。5 つのベストプラクティスを紹介します。

クエリ最適化は、スクレイプ負荷削減と並んで効果的です。特に Grafana ダッシュボードから大量のクエリが実行される環境では、ダッシュボードの更新頻度とクエリの複雑性がサーバー負荷の大部分を占めることもあります。

1. 不要なラベルを含めない

ラベルが多いと、Prometheus はそれぞれの組み合わせに対してデータを保持します。これを避けるため、クエリに含めるラベルは最小限にしましょう。

悪い例

promql
up{instance=".*", job=".*", pod=".*", namespace=".*"}

良い例

promql
up{job="api-server"}

この最適化により、クエリ応答時間を 20~30% 削減できます。

2. Range Vector の期間設定を適切に

rate()increase() 関数の Range Vector 期間は、スクレイプ間隔の最低 5 倍以上を目安に設定してください。例えば、スクレイプ間隔が 15 秒の場合、最低でも 75 秒(1 分以上)の Range Vector を指定します。この設定により、クエリの解像度と計算負荷のバランスを取ることができます。

悪い例(解像度が荒い)

promql
rate(http_requests_total[30s])  # スクレイプ間隔15sに対して2倍の不足(非推奨)

良い例(スクレイプ間隔 15s に対して、推奨される 5 倍以上)

promql
rate(http_requests_total[5m])  # 5分間の集計(推奨)

ダッシュボードの更新間隔が 1 分であれば、Range Vector は [5m][10m] 程度が適切です。

3. 多重ネストの排除

複雑に入れ子になったクエリは、メモリ使用量が増加し、クエリ応答時間も長くなります。事前に集計用メトリクスを Recording Rule で用意することで効率化します。

悪い例

promql
(sum(rate(http_requests_total[5m])) / sum(rate(http_errors_total[5m]))) * 100

この方法では、ダッシュボードが更新されるたびに複数の集計が実行されます。100 個のダッシュボードが同時にアクセスすると、100 倍の計算が発生することになります。

良い例:Recording Rule を事前に定義

yaml
# recording_rules.yml(別ファイルまたはセクション)
groups:
  - name: http_metrics
    interval: 1m
    rules:
      - record: http:request_rate:5m
        expr: sum(rate(http_requests_total[5m])) by (job)
      - record: http:error_rate:5m
        expr: sum(rate(http_errors_total[5m])) by (job)

prometheus.yml での参照設定:

yaml
rule_files:
  - '/etc/prometheus/recording_rules.yml'

この方法では、集計は 1 分ごとに 1 回だけ実行されます。その後、ダッシュボードではシンプルなクエリを使用:

promql
(http:request_rate:5m / http:error_rate:5m) * 100

Recording Rule を活用することで、ダッシュボードの応答時間を 50~80% 高速化できます。

4. offset の過度な使用を避ける

offset は前日や前週のデータと比較する際に便利ですが、過度に使用するとスケーラビリティが損なわれます。

慎重な使用例

promql
# 前日比較(許容範囲)
rate(http_requests_total[5m]) / rate(http_requests_total[5m] offset 1d) * 100

避けるべき使用例

promql
# 30日前のデータ取得(大量のメモリが必要)
rate(metric[5m] offset 30d)

長期トレンド分析が必要な場合は、外部ストレージ(InfluxDB、Thanos など)の活用を検討しましょう。

5. Group By(集計)の効率化

大量のデータセットに対して topk() を使用する場合、データを集計してから順位付けすることが効率的です。

悪い例

promql
topk(100, metric)  # 全体から 100 個選抜(重い)

良い例

promql
topk(10, sum by(job) (metric))  # ジョブごとに集計後、トップ 10 を選抜

この書き方により、クエリメモリ使用量を 50~70% 削減できることがあります。

実装の優先度と効果の大きさ

Part 5-1 で紹介した最適化施策は、すべて同じ効果があるわけではありません。限られたリソースの中で最大の効果を得るため、優先度付きで実装することが重要です。

優先度施策実装難度効果の大きさ実装期間
★★★ 最優先metric_relabel_configs による不要メトリクス削除30~50%1日
★★★ 最優先リテンション期間の短縮(15d→7d)50% ディスク削減数分
★★ 高優先度スクレイプ間隔の調整(15s→60s)50~75% 負荷削減1~2日
★★ 高優先度Recording Rule による事前集計50~80% ダッシュボード高速化2~3日
★ 低優先度ブロック圧縮の有効化20~30% ディスク節約数分
★ 低優先度クエリの微細な最適化10~20%1週間以上

実装のシナリオ

環境の状態に応じた実装順序を推奨します。

シナリオ 1:メモリ不足が課題の場合

  1. metric_relabel_configs で不要メトリクス削除(効果:30~50%)
  2. スクレイプ間隔調整(効果:追加 20~30%)
  3. Recording Rule 化(効果:ダッシュボード高速化)

シナリオ 2:ディスク容量が逼迫している場合

  1. リテンション期間短縮(効果:50%)
  2. ブロック圧縮有効化(効果:追加 20%)
  3. メトリクスフィルタリング(効果:追加 30%)

シナリオ 3:クエリ応答が遅い場合

  1. Recording Rule で事前集計(効果:50~80%)
  2. クエリの複雑度削減(効果:追加 10~20%)

実装チェックリストと次ステップ

あなたの Prometheus 環境が最適化されているかチェックしましょう。

markdown
基本設定の確認:
- [ ] スクレイプ対象のメトリクス数を把握している
- [ ] metric_relabel_configs で不要なメトリクスを削除している
- [ ] スクレイプ間隔をジョブごとに最適化している

ストレージ最適化:
- [ ] リテンション期間をビジネス要件に合わせている
- [ ] ブロック圧縮(max-block-duration)を有効化している
- [ ] ディスク使用量を定期的に監視している(df または Prometheus メトリクス)

クエリ最適化:
- [ ] Grafana ダッシュボードのクエリを監査済み
- [ ] Recording Rule で事前集計を活用している
- [ ] クエリ応答時間(slowlog)を監視している

パフォーマンス監視:
- [ ] メモリ使用量の増加傾向を把握している
- [ ] CPU 使用率のボトルネックを特定している
- [ ] スクレイプエラーを定期的に確認している

このチェックリストをすべてクリアすれば、スケーラブルで効率的な Prometheus 環境が実現できます。


前のセクション: Part 5. Prometheusの運用の基本

次のセクション: Part 5-2. HA・リテンション戦略