Edited at
Z LabDay 4

Prometheus の Remote Storage とは?

More than 1 year has passed since last update.

この記事は Z Lab Advent Calendar の四日目の記事です. 今回も, 昨日の @tkusumi さんの記事に引き続き, Prometheus に関連する内容の記事となります. Z Lab では Prometheus の Remote Storage を検証している最中なので, この記事ではその Remote Storage について紹介してみたいと思います.


どんな機能なのか?

端的にいうと Prometheus が取得したメトリクスデータを, ローカルに持つストレージだけでなく, 別のマシン上にあるストレージに格納するという機能になります.

これを実現するために, Prometheus では Remote Read/Write API の仕様を定め, Remote Storage 側で Read/Write それぞれに対しての HTTP のエンドポイントを用意することでメトリクスデータの入出力を行えるようにしています.



  • Remote Write のエンドポイント: メトリクスデータを Remote Storage に書き込むために利用される


  • Remote Read のエンドポイント: そのエンドポイントに対してクエリを送信することで, Remote Storage 側に格納されているメトリクスデータを取得するために利用される


何のために必要な機能なのか?

公式のドキュメントにもあるように, Prometheus に障害が発生した場合にはデータを削除しなければならないケースが出てくるため, Prometheus で取得したメトリクスデータを長期保存するためには, 別の長期保存に適したストレージにデータを移す必要があります. そのための手段として Remote Storage という機能が開発されました.


現時点で利用可能な実装は?

現時点で Remote Storage として利用できる実装はここにリストされています. 特に, Read と Write の両方のエンドポイントをサポートしているものは次の 4 つになります.


Cortex

https://github.com/weaveworks/cortex

Cortex は Weaveworks によって開発が進められているスケーラブルな Prometheus as a service のプロジェクトです. 実装自体はオープンソースですが, 利用するためには Weave Cloud を利用することが前提となります.


CrateDB

https://crate.io/

CrateDB はオープンソースの分散 SQL データベースの一つで, 内部の実装としてはクラスタ管理の部分などに Elasticsearch を利用しているようです. ただし, CrateDB 自身が Prometheus の Remote Storage の機能を直接提供しているわけではなく, Prometheus と CrateDB の間に crate_adapter というアダプタを置くことによって, Remote Storage として利用できるようになります.


InfluxDB

https://www.influxdata.com/

InfluxDB はオープンソースの純粋な Time Series Database の実装です. InfluxDB も以前までは Remote Storage として利用する際にはアダプタ を利用する必要がありましたが, v1.4.0 からはアダプタを利用することなく, ネイティブな機能として Prometheus の Remote Storage としてのエンドポイントを提供するようになりました. 注意しなければならない点として, クラスタ化の機能が有償版のみでしかサポートされていないという点が上げられます.


PostgreSQL

https://www.postgresql.org/

PostgreSQL は誰もが知る RDBMS の一つだと思います. Remote Storage として利用するためには, PostgreSQL に pg_prometheus という拡張機能を追加して Prometheus のメトリクスデータを取り扱えるようにした上で, prometheus-postgresql-adapter というアダプタを利用する必要があるようです.


試してみる

今回, 上述した Remote Storage の実装の中から, 簡単に構築できそうで運用のコストもあまりかからなそうな CrateDB と InfluxDB を選択して試してみました.


CrateDB

上述したように CrateDB を Prometheus の Remote Storage として利用するためには, crate_adapter というアダプタを利用する必要があります. このアダプタも利用して, 今回は次のような構成で構築を行います.

まず, CrateDB は 3 つのインスタンス用意してクラスタ化します. そして, アダプタを用意し, Prometheus からの入出力はこのアダプタを通して行います.

             +-------------+

| Prometheus |
+------+------+
|
|
v
+----------------+
| Crate Adapter |
+---+---+---+----+
| | |
| | |
| | |
+----------+ | +----------+
| | |
| v |
| +---------+ |
| +------+ CrateDB +------+ |
| | +---------+ | |
v | | v
+-------+-+ +-+-------+
| CrateDB +-------------------+ CrateDB |
+---------+ +---------+

Prometheus 側の設定は次のようにしました. url はアダプタのエンドポイントを指定し, queue_config には Remote Storage への書き込みを調整するパラメータを指定します.

remote_write:

- url: http://{{ crate_adapter の IP アドレス }}:9268/write
queue_config:
capacity: 1000000
batch_send_deadline: 10s
max_samples_per_send: 1000
max_shards: 3

remote_read:
- url: http://{{ crate_adapter の IP アドレス }}:9268/read

ここで, queue_config の各項目の意味は次の通りです.

名前
意味
デフォルト値
指定した値

capacity
Prometheus 側の書き込みキューの最大長
10000
1000000

batch_send_deadline
送信間隔の最大値
5s
10s

max_samples_per_send
一度に送信するサンプル数の最大値
100
1000

max_shards
送信の並列度
1000
3

デフォルトの設定のままだと, Remote Storage に対してのリクエストが細か過ぎていたようで, CrateDB が書き込みに対する負荷に耐えられず, 結果 Prometheus 側のキューが伸びてしまうようでした. CrateDB では Bulk Inserts によって書き込み性能を上げられるようになっているようなので, batch_send_deadlinemax_samples_per_send を共に大きくして一度のリクエストに含めるサンプル数を比較的大きな値にすることで対処しています. これに伴いキューの最大長も大きく設定しています.

また, 送信の並列度についても CrateDB のインスタンス数と同程度にするとパフォーマンスが安定することが確認できています.

このような設定により, 5k samples/second 程度のメトリクスを, Prometheus が安定して CrateDB へ書き込めるということを確認することができました. しかしながら, CrateDB で使用するディスク容量が期待していたよりも非常に大きいようで, 1 サンプルあたり 200 bytes 程度を消費しているようでした. (Prometheus の TSDB では 1 サンプルあたり 1~2 bytes しか消費しません.) これは CrateDB が純粋な TSDB ではないため, 不要なインデクスを作成してしまっていることが原因なのではないかと想像しています.


InfluxDB

InfluxDB は Prometheus の Remote Storage としての機能をネイティブに備えているため, CrateDB の場合のようにアダプタを用意する必要がありません. そのため, 構築するシステムは次のようにシンプルなものとなります.

3 つの InfluxDB のインスタンスを用意して, Prometheus からそれぞれのインスタンスに対してメトリクスデータの入出力を行います. ここで, InfluxDB 同士をクラスタ化するためには有償のエンタープライズ版を利用する必要があるため, 今回は InfluxDB 自体のクラスタ化は行っていないことに注意してください. 各 InfluxDB インスタンスへのデータの分散化は Prometheus 側に持つ Shard のロジックによって行われます.

             +--------------+

| Prometheus |
+---+--+--+----+
| | |
| | |
| | |
+----------+ | +-----------+
| | |
| | |
v v v
+----------+ +----------+ +----------+
| InfluxDB | | InfluxDB | | InfluxDB |
+----------+ +----------+ +----------+

Prometheus 側では次のように各 InfluxDB インスタンスのエンドポイントのリストを記述します. queue_config については CrateDB のときのようなパラメータの調整は不要のようだったので, 指定する必要はありません. (少なくとも数千サンプル毎秒程度の負荷では必要性は感じられませんでした.)

remote_write:

- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/write?db={{ DB 名 }}
- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/write?db={{ DB 名 }}
- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/write?db={{ DB 名 }}

remote_read:
- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/read?db={{ DB 名 }}
- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/read?db={{ DB 名 }}
- url: http://{{ InfluxDB の IP アドレス }}:8086/api/v1/prom/read?db={{ DB 名 }}

このような設定で, InfluxDB についても Remote Storage としての利用が可能であることを確認できました.

気になるのは InfluxDB 自体をクラスタ化しないことによる影響ですが, Prometheus を通してメトリクスデータを確認する限りは, Prometheus 側で上手くマージしてくれているおかげで特に問題を感じることはありませんでした. ただし, Prometheus を通さず, InfluxDB の機能を存分に利用してデータを解析したい場合などには, それぞれの InfluxDB が既に Shard されたデータしか持っていないため期待する効果が得られない場合もあると思います.


まとめ


  • CrateDB と InfluxDB を Prometheus の Remote Storage として利用することができました.

  • CrateDB を Remote Storage として利用する場合, データの容量が期待するよりも大きくなってしまうことが分かりました.

  • InfluxDB を Remote Storage として利用する場合, Prometheus を通じてメトリクスデータを確認する限りは, 無償版の機能だけでも十分利用できることが分かりました.