ELK Stackでシステム監視 kibanaのTimelion,Timeseriesでグラフ作成

今回はTimelion, VisualizeのTimeseriesを使ってグラフを作る第一歩。
例として挙げるのはcollectdで収集したネットワーク通信量RX(受信)とTX(送信)。このRXとTXはネットワークインターフェースがOSで利用可能になってからの通信総量なので単純にグラフにすると(通信が行われているなら)常に右肩上がりになる。クルマでいえば走行距離のメーターのようなの。(ただし、クルマはエンジンを停めてもメーターが0に巻き戻らないけど通信量はOSの再起動などで0に巻き戻る)
で、通信量の数値は増えたからといって「それが何なの?」的な。これを通信速度のような形に変えてやるとわかりやすいものになる筈。

VisualizeのTimeseriesの方がテキストボックスが複数行あって編集しやすいので個人的には好きだが、とりあえずTimelionでグラフを作ることにする。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 1
画面1:
先ずは、今回作成するグラフのデータRXとTXがどのようなものか確認する。
取り敢えずホスト名で絞り込む。それとcollectd_typeをif_octetsで絞る。if_octetsはバイト単位。if_packetsはパケット単位なので今回は使わない。if_errorsも使わない。さらに本来であればplugin_instanceでネットワークインターフェースを絞るのだが、今回はネットワークインターフェースが1つしかないということにしてこれは絞らないことにする。
なお、今回はTimelion, Timeseriesなのでこの絞り込み条件でSearchオブジェクトを作成保存する必要は無い。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 2
画面2:
左列のメニューからライオンのアイコン(Timelion)を選択する。
上部のテキストボックスには .es(*) が入っている筈。(初期値)
とりあえずは、 .es(hoge) が1つのグラフになると考える。hogeの部分はこれから。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 3
画面3:
.es( hoge ) のhogeの部分だが、本来はインデックスとタイムフィールドを書く。collectdで収集したデータをlogstashで受けているならそれぞれindexはlogstash-*、タイムフィールドは@timestamp決め打ちで良いかと。ただし、この記事ではこの2つは(ゴチャゴチャするのが嫌なので)省略する。

.es(index='logstash-*', timefield='@timestamp', q='hoge', metric='hage')

データを条件で絞るのにはクエリー q=hoge を使う。今回は画面1で見たようにホスト名をhoge、collectd_typeをif_octetsで絞るので q='host:hoge AND collectd_type:if_octets' となる。
使用する値として(まずは)RXの最大値を指定する。 metric='max:rx' となる。
Timelionでグラフを作るときはグラフの凡例(ラベル)を分かりやすく付けてやるのをクセ付ける方が良いかも。なのでラベル指定を追加する。形式は.es(hoge).label('文字列')のように後付けする。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').label('RX: 通信総量(bytes)')

これで上の画像のようになる。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 4
画面4:
通信総量は監視する対象としてはあまり適さないのでこれを通信速度に変えたい。
画面3で作った総量のグラフの他に1分遅れのグラフを作成する。1秒遅れでも良いんだけど、1秒ごとにcollectdでデータを取って送信してlogstashで受信してelasticsearchに溜めるというのはそれに割くCPUパワー等が勿体無いかつデータが溜まり過ぎるのでcollectdで1分のインターバルを指定して1分ずつデータを送るようにしている。Timelionで1分遅れのグラフにするには offset='ずらしたい時間' のように指定する。 また、グラフを複数表示するのは .es(1つめ), .es(2つめ) のようにする。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').label('最新の値'), 
.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx', offset='-1m').label('1分前の値')

見やすいように2行にした。

時間軸方向にずらすとその差分がずらした時間の通信量になるので、その時間で割れば速度になる。
つまり一定時間で分割して差分を取れば良いわけ。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 5
画面5:
差分のグラフを作成する。作り方は .es(最新).subtract(.es(1分遅れ)) となる。これで1つのグラフ。やはり最後にラベルを指定する。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx', offset='-1m')).label('RX: 1分間の通信量(bytes)')

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 6
画面6:
ここまでRX(受信)だけなのでTX(送信)も追加する。単純にここまで作ったRXのグラフのrxの部分をtxに変えたのがTXのグラフ。それを並べて , を挟む。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx',offset='-1m')).label('RX: bytes/分'), 
.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx',offset='-1m')).label('TX: bytes/分')

見やすいように2行にした。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 7
画面7:
これで通信量から速度になったが、bytes/分という単位は慣れないかもしれない。そこでよく使うbits/秒(bps)に変える。bytes/分は60で割ればbytes/秒(ただし1分間の平均速度)になる。また、bytes/秒は8を掛ければbits/秒になる。つまり60で割って8掛けるので結果的に7.5で割ることになる。
これは .es(グラフ).divide(7.5) と書くことができる。
ちなみに 7500で割ればKbps、7500000で割ればMbps。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx',offset='-1m')).divide(60).label('RX: bits/秒'), 
.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx',offset='-1m')).divide(60).label('TX: bits/秒')

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 8
画面8:
ところで、人によってはRTとTXを同じ側に表示するのを嫌うかもしれない。折れ線が入り組むと見にくい。上の画像のような1エリアに複数のグラフを描く場合は棒グラフは他のグラフを隠すのであまりオススメしない。
そこでたとえばTXをマイナス値で表示してエリア分けしてみる。TXの差分の取り方を逆にするだけ。

.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:rx', offset='-1m')).divide(7500).label('RX: Kbps'), 
.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx', offset='-1m').subtract(.es(q='host:hoge AND collectd_type:if_octets', metric='max:tx')).divide(7500).label('TX: Kbps')

これで上の画像のようになる。

通信総量なのでOSを再起動するなどで差分がマイナス値の起動前通信総量となる。再起動前の通信総量が巨大な数値だとグラフが使い物にならない状態になる。グラフ毎に.min(0)や.max(0) を付けるなどしてマイナス値またはプラス値を表示させないようにする。
または、プラス値しか存在しえないのであれば、全てのグラフの最後に.yaxis(min=0)を付けるとグラフ毎に書く必要がない。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 9
画面9:
ここまでTimelionで作ったテキストボックスの内容をコピー(してVisualizerに貼り付けることに)する。
左列のメニューでVisualizerをクリックし、新しいVisualizeオブジェクト作成のために(新規作成)をクリック。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 10
画面10:
Timelion Expressionのテキストボックスにコピーした内容を貼り付ける。
[]を押してグラフが正しく描かれることを確認する。(時間範囲を変えるなどもする)
もし、折れ線が嫌で棒グラフにしたいということであれば .es(グラフ).label('文字列').bars(stack=false width=3) のようにする。棒グラフは初期値がStack(重ねる)なので注意。重ねたい場合を除いてstack=falseを書く方が安全。(マイナス値があってstackさせるとグラフとしては破綻する)棒の太さはwidthで指定。label()とbars()の前後の位置関係はどっちでも良い。
問題無いようであれば[Save]で名前を付けて保存する。

Timelion, VisualizeのTimeseriesを使って自在にグラフを作る 11
画面11:
1つ前の画面10で作成したVisualizeオブジェクトをDashboardに[Add](追加)して保存する。
上の画像では一番下のグラフが今回作成したネットワークインターフェースの送受信速度(Kbps)、ただし1分間の平均速度。棒グラフにしてみた。

今回はTimelion, Timeseriesによるグラフ作成のキホンのキでExcelでいえばワークシート関数を初めて書くくらい。これが思い通りに書けて何でも出来る気になってくるととんでもないのを作ってelasticsearchのメモリが足りないとかになるのでほどほどに。

2018年2月19日修正: 初稿は間違った置換をしたクエリー .es(q='hoge, hage')で公開してたので修正した。正しくは(q='hoge AND hage')でした。

関連記事: