数百万のメトリクスを支配せよ:大規模Prometheusシャード設計の「極意」
こんにちは。システムが成長し、メトリクスが数百万のオーダーに達したとき、多くのエンジニアが「Prometheusの限界」に直面します。単一のインスタンスではCPUが飽和し、メモリが溢れ、スクレイピングの遅延がアラートを鳴らし続ける……。
今日は、そんな悪夢を終わらせるための「Prometheus水平分散スクレイピング」の設計思想についてお話しします。これをマスターすれば、どれだけサービスが巨大化しても、あなたの監視基盤は涼しい顔で動き続けるようになります。
—
1. なぜ「単一のPrometheus」では限界が来るのか?
Prometheusは非常に優秀ですが、スクレイピング(データの収集)とストレージ(データの保持)を同じプロセスで行う設計上、ターゲット数が増えすぎると以下のボトルネックに突き当たります。
- スクレイピングのオーバーヘッド: HTTPリクエストの並列処理とパース処理でCPUを使い切る。
- メモリ制約: メトリクス数(時系列データの多さ)に比例して、インデックス保持のためのメモリが枯渇する。
そこで登場するのが「シャード(Sharding)」という概念です。
—
2. アーキテクチャの心臓部:Consistent Hashing と Target Allocator
大規模環境では、「どのPrometheusがどのターゲットをスクレイピングするか」を動的に割り当てる仕組みが必要です。ここでConsistent Hashing(一貫性ハッシュ法)が重要になります。
なぜ Consistent Hashing なのか?
ターゲットの増減やスクレイパー(Prometheus)の増減が発生した際、ハッシュ値を再計算して割り当て先を動的に決定することで、「最小限の再配置」で負荷分散を実現できるからです。
推奨構成:Prometheus Agent + Target Allocator
最近のベストプラクティスは、Prometheusを「スクレイピング専用(Agentモード)」として動かし、収集したデータをThanos Receiverへリモートライトする構成です。
1. Target Allocator: 監視対象のサービスディスカバリを行い、Consistent Hashingで各Prometheusに負荷を割り振る。
2. Prometheus Agent: 割り当てられたターゲットのみをスクレイピングし、ストレージには持たず即座に送信。
3. Thanos Receiver: 送られてきたメトリクスを統合・保存し、クエリを統合する。
—
3. 「HelloWorld」的なセットアップ:まずは体験する
まずは、小さな環境でその挙動を理解しましょう。今回はPrometheus単体でのシャード設計の第一歩として、「スクレイピングの分割」をシミュレートします。
ステップ1:Prometheus Agent モードの起動
まずはスクレイピング専用として起動します。設定ファイル `prometheus.yml` に以下を記述してください。
global:
scrape_interval: 15s
リモートライト設定:ここでThanos Receiver等へ流し込みます
remote_write:
- url: “http://thanos-receiver:19291/api/v1/receive”
自身のストレージは最小限に抑える(Agentモード)
storage:
tsdb:
path: /prometheus/data
retention.time: 2h
ステップ2:ターゲットの分散(Relabelingの魔法)
これが最も重要な「現場の技」です。Prometheusの `relabel_configs` を使い、ターゲットをハッシュ化して動的に振り分けます。
scrape_configs:
- job_name: ‘kubernetes-pods’
kubernetes_sd_configs:
- role: pod
# 【ここが肝】ターゲットのハッシュ値を見て、このノードが担当するかを決定
relabel_configs:
- source_labels: [__meta_kubernetes_pod_name]
modulus: 2 # シャード数(今回は2台構成を想定)
target_label: __tmp_hash
action: hashmod
- source_labels: [__tmp_hash]
regex: 0 # 0番目のシャードが担当するターゲットだけ抽出
action: keep
—
4. 運用エンジニアとして知っておくべき「極意」
これだけは覚えておいてください。
1. シャーディングのキーは慎重に: `__meta_kubernetes_pod_name` を使うのが一般的ですが、Podの入れ替わりが激しい環境では、一貫性ハッシュの計算が頻繁に走り、スクレイピングに隙間ができることがあります。
2. 「ノイズのない」メトリクスこそ正義: そもそも、全てのメトリクスをスクレイピングする必要はありますか? `metric_relabel_configs` で不要なメトリクスを収集前に落とすこと。これだけで負荷は劇的に下がります。
3. 観測不可能性を殺せ: どのノードがどれくらいのターゲットを抱えているか、`prometheus_sd_discovered_targets` メトリクスで常に監視してください。
—
最後に:怖がる必要はありません
数百万メトリクスという数字を聞くと腰が引けるかもしれませんが、やっていることは「適切な粒度で分割し、責任を分散させる」というコンピュータサイエンスの基本そのものです。
まずは、1台のPrometheusで苦しんでいるターゲットを半分に分けるところから始めてみてください。それができれば、あとはスケールアウトさせるだけ。あなたの監視基盤は、今日からより堅牢で、より静かなものへと進化し始めます。
もし設定で行き詰まったら、いつでも戻ってきてください。現場で培った「震えるほど役立つ知見」を、また共有しますから。