InfluxDB をちょっとさわってみた
InfluxDBとは
メトリクスやイベントといった時系列データを格納するのに適したデータストアです。
ちなみに go で書かれています。
ちなみに 2013のOpen Source Rookiesに選ばれました。
InfluxDBの特徴
RRDやMySQLに時系列データを格納する場合と比較して、InfluxDBの特徴を紹介します。
バックエンドは LevelDB
LevelDBとは、キーでソートされた状態で可能されたKVSです(Google製)。詳しくはこのへん参照のこと。
- http://en.wikipedia.org/wiki/LevelDB
- https://code.google.com/p/leveldb/
- https://speakerdeck.com/smly/influxdb-and-leveldb-inside-out
将来的にLevelDBからほかの実装に変わる可能性もありそうです。
databaseとseries
RDBMSのdatabaseとtableと同じく、databaseとseriesの2階層でデータの管理ができます。
schema-less
RDBMSのテーブル定義やRRDのdata sourceの定義と違い、格納するデータ構造を予め定義しておく必要がありません。
過去のデータも登録可能
RRDと違って、任意の時点のデータを登録可能です。
SQL風の問い合わせ言語
結果はPerlの構造体で書いてますが、ほんとうはJSONで返ってきています。
- 時刻で範囲指定
select reqtime, url from web9999.httpd where time > now() - 1h limit 1000; [ { columns => ["time","sequence_number","reqtime","url"], name => "web9999.httpd", points => [ ["1392030886","60703580001","0.21","/view/entry"], ["1392030885","60703560001","0.07","/login/error"], ["1392030884","60703540001","0.32","/login/"], ... ] } ]
- カラムの値で絞り込み
select reqtime, url from web9999.httpd where reqtime > 2.5; [ { columns => ["time","sequence_number","reqtime","url"], name => "web9999.httpd", points => [ ["1392030883","60703520001","2.81","/list/entry"], ["1392030878","60703420001","2.72","/view/entry"], ["1392030877","60703400001","2.94","/login/error"], ... ] } ]
- カラムの値で絞り込み(正規表現)
select reqtime, url from web9999.httpd where url =~ /^\/login\//; [ { columns => ["time","sequence_number","reqtime","url"], name => "web9999.httpd", points => [ ["1392030885","60703560001","0.07","/login/error"], ["1392030884","60703540001","0.32","/login/"], ["1392030881","60703480001","0.78","/login/error"], ... ] } ]
- 複数seriesに同時に問い合わせ
select * from /web9999\..*/; [ { columns => ["time","sequence_number","sys","user"], name => "web9999.cpu", points => [ ["1392030886","60703590001",3,57], ["1392030885","60703570001",9,1], ["1392030884","60703550001",28,42], ... ] } { columns => ["time","sequence_number","reqtime","url"], name => "web9999.httpd", points => [ ["1392030886","60703580001","0.21","/view/entry"], ["1392030885","60703560001","0.07","/login/error"], ["1392030884","60703540001","0.32","/login/"], ... ] } ]
- 複数seriesに問い合わせ、結果をmergeする
select reqtime, url from web9999.httpd merge web0001.httpd; [ { columns => ["time","sequence_number","reqtime","url","_orig_series"], name => "web9999.httpd_merge_web0001.httpd", points => [ ["1392030886","60706000001","1.09","/view/entry","web0001.httpd"], ["1392030886","60703580001","0.21","/view/entry","web9999.httpd"], ["1392030885","60705980001","1.53","/login/error","web0001.httpd"], ... ] } ]
select reqtime, url from merge /.*\.httpd$/
のように、merge対象のseriesを正規表現で指定できるとドキュメントには書いてありますが、まだ実装されてないみたいです。 https://github.com/influxdb/influxdb/issues/72
集約関数が豊富
COUNTやMIN, MAX, MEANなどなど。
RRDのDERIVEと同等のことができるDERIVATIVEや、パーセンタイルを算出するPERCENTILEもあります。
MIN,MAXはRDBMSで算出するのはめんどうくさい、DERIVATIVEはかなりめんどくさいので便利だと思います。
ちなみにDERIVATIVEとは、( v(t1) - v(t0) ) / (t1 - t0) を時刻 t1 の値とする関数です。具体的には、ネットワークの転送バイト数など、増加カウンタの値をデータとして格納しておき、グラフ描写時には Mbps (増加割合)を計算して使いたいときに便利です。
GROUP BY によるダウンサンプリングが可能
例えば1分ごとのデータを格納している場合、
select mean(sys) from web9999.cpu group by time(15m);
で、15分おきにまびいてその間の平均値を求められます。
RRDでは一つのDSについて、保持粒度の異なる複数のRRAを定義しますが、それと同じ事をオンデマンドでできるわけです。
Continuous Query
問い合わせの度にいちいちGROUP BYでダウンサンプリングを行うのは効率的ではありません。そこで Continuous Query というものを登録しておくことで、定期的にダウンサンプリングを行いデータをまびくことができます。
用途を限定したRDBMSのtriggerのようなものです。
例えば
select mean(sys) from web9999.cpu group by time(15m) into web9999.cpu.15m;
のような Continuous Query を登録しておくと、自動的に web9999.cpu.15m にまびいたデータを入れてくれます。
この Continuous Query と次の Regularly Scheduled Deletes (後述)を活用すると、
- もっとも粒度の小さい1分おきのデータは2週間分保持
- 15分の平均データは2ヶ月分保持
- 60分の平均データは永久保持
といったことが可能になりそうです。
Regularly Scheduled Deletes
指定した期間より古いデータを自動的に削除する機能があるようですが、InfluxDB 0.5.4ではまだ実装されていないようです。 https://github.com/influxdb/influxdb/issues/98
InfluxDB のいまいちなカワイイところ
InfluxDB v0.5.4 (git: 93e93fa8986ab782b60087aa5b194113af8e16e5) での感想です。
将来的には修正されるものもあると思うので注意してください。
データとして構造をもったJSONを登録できない
そういう仕様なので、フラットに展開して入れるしかないと思います。
{ "a": { "i": "foo", "j": "bar", }, "b": 3 }
を
{ "a.i": "foo", "a.j": "bar", "b": 3 }
のような感じに平坦化するとか。
集約関数を複数カラムに使えない (修正済み)
select max(col1), max(col1) の結果の columns は ["max", "max"] になるので、データは返ってくるけどどっちが col1 の max が区別ができない。
SQLの様にカラムにもasで別名が付けられるようになればいいんだけど。(seriesにはasで別名をつけられる)
issue にも上がっているのでそのうち対応されるかも。
https://github.com/influxdb/influxdb/issues/69 → 対応されました! v0.5.0-rc3にはカラムの別名が使えるようになると思います。
v0.5.1だとasを使ってこんな感じでできるようになりました。
[9] pry(main)> select mean(sys) as sys, mean(user) as user from myhost.cpu group by time(10m) limit 10; +---------------+--------------------+--------------------+ | myhost.cpu | +---------------+--------------------+--------------------+ | time | sys | user | +---------------+--------------------+--------------------+ | 1359676200000 | 23 | 52.599999999999994 | | 1359675600000 | 28.9 | 41.29999999999999 |
カラム名に予約語をつけると問い合わせ不能になる
例えば「in」というカラム名をつけると、select in from がエラーになる。select 'in' from とすればいいんだけど、今度は集約関数が使えなくなる。select count('in') は動かない。
あるdatabase内のseriesの一覧を得る API がない
select * from /./ limit 1で代用するしかないみたい。
と思っていたがlist series というクエリーを投げればよい。
が!、バグってて動かない。https://github.com/influxdb/influxdb/issues/358
データのバックアップ方法が不明
公式ドキュメントにバックアップについて書いてある文章がない。
LevelDBのデータファイルをファイルコピーすればいいのかもしれないけど、整合性が保たれるか、バックアップデータとして正常に使えるのか不明。
バックアップに限らず運用周りはこれからの感じがする。
目玉の Continuous Query 周りがいろいろアレ
database を削除しても Continuous Query の定義は消えないで残る。(仕様?)
前述の通り、カラム名の別名付与ができないので、select max(sys), max(user) from myhost.cpu into ... な Continuous Query を定義してselectすると、maxが2つ返ってきて区別できない。
今のところ、カラムごとに別の Continuous Query を定義するしかない。→カラムの別名が実装されたv0.5.0-rc3以降なら問題ないかも
v0.5.1だとこんな感じでできるようになりました!!
[25] pry(main)> select mean(sys) as sys, mean(user) as user from myhost.cpu group by time(10m) into myhost.cpu.10m [24] pry(main)> select * from myhost.cpu.10m limit 10; +---------------+-----------------+--------------------+--------------------+ | myhost.cpu.10m | +---------------+-----------------+--------------------+--------------------+ | time | sequence_number | sys | user | +---------------+-----------------+--------------------+--------------------+ | 1359676200000 | 1 | 23 | 52.599999999999994 | | 1359675600000 | 1 | 28.9 | 41.29999999999999 |
Continuous Queryを定義した時点で、当該seriesにある前データ(過去のも)を処理してダウンサンプリングする。過去のデータを対象にできるのはこのときのみ。
なので、CQを定義した後で過去のデータを入れてもダウンサンプリングされない。検証時に過去のデータを入れてる時や、実運用でも過去のデータを入れる要件がある場合は注意。
ただ、再計算できるようにするというissueが上がっているので要注目。
https://github.com/influxdb/influxdb/issues/211
ほか
rootのパスワードの変更
↓で、できます。
curl -u root:root -X POST 'http://127.0.0.1:8086/cluster_admins/root' -d '{"password": "root"}'