prometheusの remote write (influxdb)

はじめに

prometheusは、データを永続的に保管する目的で使うのはあんまりよくないと書かれています。

If your local storage becomes corrupted for whatever reason, your best bet is to shut down Prometheus and remove the entire storage directory.

では永続的に保管するにはどうするかというと、remote writeというリモートストレージにデータを書き込む方法が提供されています。

対応しているリモートストレージの一覧がドキュメントに記載されています。 念のために列挙しますと以下の通りです。

  • AppOptics: write
  • Chronix: write
  • Cortex: read and write
  • CrateDB: read and write
  • Gnocchi: write
  • Graphite: write
  • InfluxDB: read and write
  • OpenTSDB: write
  • PostgreSQL/TimescaleDB: read and write
  • SignalFx: write

このうち、今回はInfluxDBを試してみました。

InfluxDB へ remote writeする

InfluxDBへremote write する方法は2つあります。

  • prometheusが提供している remote_storage_adapterを利用する方法
  • InfluxDBが対応している prometheusのremote write 向けAPIを利用する方法

使うとどのようになるのかをそれぞれ実験してみます。

prometheusが提供している remote_storage_adapterを使う方法

remote_storage_adapter というものがPrometheusオフィシャルで提供されているのでそれを利用します。

利用方法は オフィシャルに記載がある通りなのですが、

remote_storage_adapter をビルドし、 2つのオプション

を指定して起動します(ここではローカルにInfluxDBが動いている前提で書かれています)。

./remote_storage_adapter -influxdb-url=http://localhost:8086/ -influxdb.database=prometheus

次に、prometheusのremote_write設定に remote_storage_adapter を指定します。

remote_write:
  - url: "http://localhost:9201/write"

この状態でPrometheusをreloadすると、InfluxDBにデータが送信され始めます。(remote_write_adapterはデフォルトでは9201番ポートをListenします)

  • InfluxDBが提供しているAPIを利用する

InfluxDBのドキュメントに記載されている方法を利用します。

1つ目の方法と違い、PrometheusとInfluxDBのほかに用意する必要はありません。

prometheusのremote_write設定にInfluxDBを指定するだけで良いです。

remote_write:
  - url: "http://localhost:8086/api/v1/prom/write?db=prometheus"

この状態でPrometheusをreloadすると、InfluxDBにデータが送信され始めます。

remote_write されたデータを確認する

InfluxDB上のデータを確認してみます。

prometheusが提供している remote_storage_adapterを使う方法

$ influx
> use prometheus
> show series

とテーブルを見てみると、メトリック名でテーブルが作られているのがわかります。

> select * from tsdb_wal_fsync_duration_seconds
name: tsdb_wal_fsync_duration_seconds
time                instance       job        quantile value
----                --------       ---        -------- -----
1513046600853000000 localhost:9090 prometheus 0.5      0.001505024
1513046600853000000 localhost:9090 prometheus 0.9      0.001505024
1513046600853000000 localhost:9090 prometheus 0.99     0.001505024
1513046615853000000 localhost:9090 prometheus 0.5      0.000018808
1513046615853000000 localhost:9090 prometheus 0.9      0.001161131
1513046615853000000 localhost:9090 prometheus 0.99     0.001161131
1513046630853000000 localhost:9090 prometheus 0.5      0.001161131
1513046630853000000 localhost:9090 prometheus 0.9      0.001505024
1513046630853000000 localhost:9090 prometheus 0.99     0.001505024
1513046645853000000 localhost:9090 prometheus 0.5      0.001161131
1513046645853000000 localhost:9090 prometheus 0.9      0.001505918
1513046645853000000 localhost:9090 prometheus 0.99     0.001505918
1513046660853000000 localhost:9090 prometheus 0.5      0.000883545
1513046660853000000 localhost:9090 prometheus 0.9      0.001505918
1513046660853000000 localhost:9090 prometheus 0.99     0.001505918
1513046675853000000 localhost:9090 prometheus 0.5      0.000801818
1513046675853000000 localhost:9090 prometheus 0.9      0.001505918

このように、ちゃんと15秒ごとにデータがたまっているのがわかります。

  • InfluxDBが提供しているAPIを利用する
$ influx
> use prometheus
> show series

とテーブルを見てみると、_という名称でテーブルが作られているのがわかります。メトリック名はname に入っていますね。

> select  * from _ where __name__='tsdb_wal_fsync_duration_seconds'
name: _
time                __name__                        branch call code dialer_name endpoint event f64         goversion handler instance       interval job        le listener_name method quantile queue reason revision role rule_type scrape_job slice version
----                --------                        ------ ---- ---- ----------- -------- ----- ---         --------- ------- --------       -------- ---        -- ------------- ------ -------- ----- ------ -------- ---- --------- ---------- ----- -------
1512977394388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.5
1512977394388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.99
1512977394388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.9
1512977409388000000 tsdb_wal_fsync_duration_seconds                                             0.001188145                   localhost:9090          prometheus                         0.99
1512977409388000000 tsdb_wal_fsync_duration_seconds                                             0.001188145                   localhost:9090          prometheus                         0.9
1512977409388000000 tsdb_wal_fsync_duration_seconds                                             0.000020984                   localhost:9090          prometheus                         0.5
1512977424389000000 tsdb_wal_fsync_duration_seconds                                             0.001188145                   localhost:9090          prometheus                         0.9
1512977424389000000 tsdb_wal_fsync_duration_seconds                                             0.000938485                   localhost:9090          prometheus                         0.5
1512977424389000000 tsdb_wal_fsync_duration_seconds                                             0.001188145                   localhost:9090          prometheus                         0.99
1512977439388000000 tsdb_wal_fsync_duration_seconds                                             0.000938485                   localhost:9090          prometheus                         0.5
1512977439388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.99
1512977439388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.9
1512977454388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.99
1512977454388000000 tsdb_wal_fsync_duration_seconds                                             0.001899241                   localhost:9090          prometheus                         0.9
1512977454388000000 tsdb_wal_fsync_duration_seconds                                             0.000935074                   localhost:9090          prometheus                         0.5
1512977469389000000 tsdb_wal_fsync_duration_seconds                                             0.008376216                   localhost:9090          prometheus                         0.9
1512977469389000000 tsdb_wal_fsync_duration_seconds                                             0.000935074                   localhost:9090          prometheus                         0.5
1512977469389000000 tsdb_wal_fsync_duration_seconds                                             0.008376216                   localhost:9090          prometheus                         0.99

このように、ちゃんと15秒ごとにデータがたまっているのがわかります。 InfluxDBオフィシャルの実装を利用する場合は select * で検索すると残念な見た目になるので、ちゃんと 利用するタグを指定する必要がありそうです。

終わりに

Prometheusのremote write機能を利用してInfluxDBへデータを保存する方法を確認しました。

Prometheus側で用意した実装とInfluxDB側で用意した実装では、格納のされ方が違うので、互換性がないことがわかりました。どちらの方法を使うかはきちんと決めてから利用しましょう。

windows 10 fall creators update でなんか環境変数が設定しにくくなった気がするのでPowerShellで環境変数を設定することにしたっぽい。

[Environment]::GetEnvironmentVariable(<環境変数名>,[EnvironmentVariableTarget]::User)

で現在の値がゲットできる。

[Environment]::SetEnvironmentVariable(<環境変数名>,<値>,[EnvironmentVariableTarget]::User)

でセットできる。

pathを追加する場合は

[Environment]::SetEnvironmentVariable("path",[Environment]::GetEnvironmentVariable("path",[EnvironmentVariableTarget]::User)+<値>,[EnvironmentVariableTarget]::User)

こんな感じ。

DHCP relay agent と giaddr と source address

DHCP relay agentとは

DHCP パッケットをDHCPサーバへ転送するエージェント。

DHCPclient -- DHCPrelayagent -- DHCPserver

みたいな感じで、DHCPclientとDHCPserverが同一セグメントにいない場合に間に入ってくれるやつ。

仕組みみたいなもの

clientから、DHCPDISCOVERがブロードキャストされると、relayagentは、giaddrにパケットを受け取ったインターフェースのアドレスを入れ、 serverがある方のインターフェースからパケットを送信

serverは受け取ったDHCPDISCOVERをもとにDHCPREPLYパケットを作成。このとき、OFFERするIPAddresは、giaddrを見て決める。 作成したパケットは、giaddr宛に送信。

relayagentは、DHCPREPLYパケットを受け取ったあと、giaddrを見て、送信するインターフェースを決め、そこからclientに向けてパケットを送信する。

relayagent から server に送信するとき、IPAddressはどれを使う?

DHCPclient -- ○DHCPrelayagent● -- DHCPserver

  • serverがいる方のアドレス(●)
  • clientがいる方のアドレス(○) 通常、ある端末からある端末へIPパケットを送信する時の、source addressは、宛先端末へ近いインターフェースのものを使う。

つまり、serverがいる方。ただ、serverからの戻りは、giaddrが宛先になっています。(でないとrelayagentがどのアドレスからそのパケットを送信すればよいか判断できなくなるため RFCに記載がある。)

困ること

relayagent と serverの間に、ステートフルなFirewallがあったりすると…… relayagentから送信したパケットの戻りが、同一ステートとみなされず、破棄されることが。

実際の実装

Cisco IOSは、relayagentのsource addressをgiaddrに合わせている。ASAは、serverに近い方のアドレスだったのを、IOSに合わせる変更を行っている (CSCuo89924)。

Juniperは、紆余曲折あったようで 最初はsource addressをgiaddrに合わせていて変更不可だったのを、serverに近い方のアドレスに変更し、最後には、source addressをgiaddrに合わせるのをデフォルトとして、設定で変更できるようにしている。

Linux(CentOS7)では、source addreessは、宛先端末へ近いインターフェースのものが使われる。

Firewall側で対応してほしい

ステートレスに扱うよう、対応してほしい。