influxDB + Grafanaに入門する

背景
====

可視化ツールとしてはElasticsearchを常に使っていたのですが、いわゆるサーバーのメトリクスデータのような数値データを記録するのであれば、influxDBというのもあるということでお試し。

influxDB + Grafanaの概要
====

influxDB
----

influxDBは時系列DB (Time series database) と呼ばれるソフトウェアに分類される。時系列DBはその名の通り、時間を追うに従って変化するようなデータを格納する機構を備えたDBで、[英語版Wikipediaだと記事ページがある](https://en.wikipedia.org/wiki/Time_series_database)が、これによればRRDToolも時系列DBとされるよう。

RRDToolとの比較も考えつつ、influxDBの特徴を上げると以下のような点。

* データ登録はREST APIを通じてjsonで可能。
* デフォルトで認証機構を備えている。
* クエリはSQLに準じた文法を使用することが可能。
* Web UIを備えており、GUIでインタラクティブにクエリ結果を確認できる。

Grafana
----

GrafanaはKibanaからフォークされて作られたダッシュボードツールですが、influxDBに特化したものではなく、GraphiteやCloudWatchとも連携ができる。こちらもデフォルトで認証機構を備えている。

手順
====

influxDBとGrafanaの起動
----

手っ取り早いので公式のDockerイメージをDocker Composeで立ち上げました。

**2016-12-22 追記：** Grafanaのコンテナ設定にData Volumeの記述を追加。Grafanaのダッシュボード、ユーザー設定等を永続化するために、sqliteのディレクトリを保存しておく必要があったため。ダッシュボード設定等はMySQLなどの外部DBに保存させることも可能だが、簡略化の意味で、今回はデフォルトで用意されるsqliteを使用することにした。（参考： [Grafana - Configuration](http://docs.grafana.org/installation/configuration/#database) ）

```yaml:docker-compose.yml
version: "2"

services:
  influxdb:
    image: influxdb
    ports:
      - "8083:8083"
      - "8086:8086"
    volumes:
      - /tmp/influxdb:/var/lib/influxdb

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - /tmp/grafana:/var/lib/grafana
```

influxDBで開いている2つのポートのうち、`8083`がWeb UIで`8086`がREST APIのエンドポイントに当たります。またデータは`/var/lib/influxdb`に保存されるので、データボリュームとしてホストOSと同期させています。

GrafanaはWeb UI用のポートを開けるだけ。Kibanaの場合は`kibana.yml`でElasticsearchとの接続設定をしていましたが、GrafanaはWeb UI上でDBとの接続を設定するので、この時点では特に設定ファイルなどの考慮は不要です。

influxDBとGrafanaの接続
----

`http://(Docker HostのIP):3000`にウェブブラウザからアクセスし、左上のアイコンから「Data Sources」を選び、「Add Data Source」から`http://(Docker HostのIP):8086`へ接続します。

![Grafana Add Data Source](https://qiita-image-store.s3.amazonaws.com/0/19465/e63784ac-b65d-69e4-9724-f4e5485f5db5.png)

なお認証ユーザーIDとパスワードの初期設定は、influxDBがroot:root、Grafanaがadmin:admin。

influxDBへのデータ投入
----

今回はPythonを使いましたが、その前に前提としてinfluxDBの構造の話。

### influxDBの構造

* `Database` : RDBMSにおけるデータベースと同様、最も大きなデータ単位。`Database`はデータ投入前に作成しておく必要がある。
* `Measurement` : RDBMSにおけるテーブルの位置。
* `Retention Policy` : データの保存期間を定めた`DURATION`と、influxDBクラスタ内でいくつデータのコピーを保持するかを定めた`REPLICATION`からなるデータの保存ポリシー。基本的には`Database`に対して紐付ける形で使用する。

まだお試しなのでちゃんと使っていないのですが、`Retention Policy`があるのがいいですね。データを無制限に保存して容量が溢れてしまうような事象を防げるのと、可用性を担保できるのと。

### influxDBのデータ構造

Elasticsearchだとjsonを適当に突っ込むとそれでもう使えたので、APIから取得したjsonをそのまま投げるようなズボラ運用もできたんですが、influxDBの場合はjsonに含むべきデータ構造が決められています。

* `measurement` : どの`measurement`にインポートするかを指定。
* `fields` : いわゆるデータそのものをキーバリューの形式で指定する。キーは文字列型限定ですが、バリューは文字列の他にfloat, integer, booleanにも対応しています。また複数の`field`を含めることも可能。
* `tags` : オプショナルなデータを指定する。例えばサーバーのメトリクスデータを入力しているのであれば、サーバー名を指定するのが`tags`。こちらも複数含めることはできますが、文字列型のみに対応している点に注意。
* `timestamp` : データのタイムスタンプ。時系列データの要と言ってもよい部分。指定しなかった場合は入力処理が行われた時刻が自動的に適用されます。なお、influxDBは *UTCのみ対応です。*

`fields`と`tags`の使い分けが若干恣意的なところがありそうですが、大きな違いとして`fields`はインデックスされませんが、`tags`はインデックスされます。従ってクエリをかけるときに例えば`GROUP BY`句を使ったりすると思いますが、ここで使用するのは`tags`の方です。検索等に使うメタデータが`tags`で、時系列で変化するデータが`fields`と押さえればよいかと。変化するデータ、例えばCPU使用率が80%のとき、などというクエリは普通かけないので、そう考えると`fields`がインデックスされないというのは納得ですね。

### データ投入処理

簡単にソース示します。

```py
from influxdb import InfluxDBClient

client = InfluxDBClient('127.0.0.1', 8086, 'root', 'root', 'sample')

# databaseの存在を判定し、作成前であれば新規作成
dbs = client.get_list_database()
sample_db = {'name' : 'sample'}
if sample_db not in dbs:
    client.create_database('sample')

# インポートするjsonデータを作成
import_array = [
{
  "fields" : {
    "cpu" : 50.0,
    "mem" : 20.0,
  },
  "tags" : {
    "category" : "fuga",
    "machine" : "web02"
  },
  "measurement" : "metrics"
}
]

# データ投入
client.write_points(import_array)
```

簡単です。`InfluxDBClient`に直にパスワード書いていますが、本運用する際はハードコーディングはやめるべきところです。データのjsonについては先程も書いたとおり、`fields`や`tags`を複数入れてみています。これでMachineごとのグラフを描いたりすることができます。

Grafanaでの可視化
----

GUIでの操作になるので詳細は割愛しますが、KibanaのようにDashboard上にPanelと呼ばれるパーツを配置していく形で可視化していきます。PanelにはGraphのほか、最新の値だけを数字で大きく表示させたりできるSingle stat、Markdown等で文章が書けるTextといったものもあり、自由度は高いです。

またGraph等で表示するデータを指定する際は、SQL文で設定するため、わかりやすい一方でinfluxDBにおけるSQL文の使用方法は押さえておく必要があります。とはいえGUI上で候補をクリックしながら組み合わせてSQLを作れるので、多少曖昧な理解でもなんとかなります。とても楽です。

使用感、ES+Kibanaと比べて
----

Elasticsearch + Kibanaの使用感をイメージすると、インプットするときに設定する必要のあるjsonのキーが定められていたり、勝手が違うところに戸惑いはしましたが（というよりはjsonなら何でも突っ込めて程々に検索できちゃうESが神）、使用感としてはやはり「簡単にデータの可視化ができる」、しかも見やすいという点では一致しています。はじめはElasticsearchと競合するのかな？と思っていましたが、現在では両者は明確に異なる守備範囲を持ったツールとして理解しました。

* influxDB : 文字通り時系列データであり、時を経て「変化」する値に関し、その変化を可視化する点に特化されている。`fields`には文字列も入力できるが、インデックスされていないため検索用途には向かない。
* Elasticsearch : Kibanaでの可視化、グラフ描画が便利なので忘れていたが、こちらは「全文検索エンジン」。投入した大量の文字列データから検索をかけたい場合にはこちら。

例えばMySQLを運用するにあたり、スロークエリログを長期間取り溜めて解析を行いたい場合にはElasticsearchが適切ですし、トラフィック量を監視したいのであればElasticsearchでも可能ではありますが、棲み分けとしてはinfluxDBということになりそう。