metrics収集ツール、Diamondで遊んでみた

# はじめに
metrics収集ツール、Diamondを使ってみたメモです。
時系列データの保存、および可視化基盤としては定番のGraphite+Grafana を使いました。

# 時系列データ保存、可視化
まずはじめに、Graphite, Grafanaを簡単に紹介します。
Graphiteは、以下のようなサービスを提供します。

* 時系列データを保存
* 保存したデータを取得するためのAPI

Graphite単体で可視化までできるのですが、洗練されてるとはいいにくいので、GraphiteはAPIを提供するに留め、ダッシュボードの生成等、可視化部分は別のツールを使うことが多いようです。この可視化ツールとして、今回はGrafanaを使いました。

Grafanaを使うことで、例えばこんな感じのスタイリッシュなダッシュボードが簡単に作れます。

![grafana.png](https://qiita-image-store.s3.amazonaws.com/0/12053/c7e674cb-9c83-aa06-edcf-2abd423fdb29.png)

GraphiteやGrafanaについては以下のサイトが参考になります。
[Chef Handlers + Graphite で Chef の実行結果を可視化する](http://hogehuga.inokara.com/2014/05/06/chef-handler-graphite.html)
[Graphite Documentation](https://graphite.readthedocs.org/en/latest/index.html)
[Graphite と Grafana を 1 時間位使ってみたメモ](http://inokara.hateblo.jp/entry/2014/05/28/230025)
[Grafanaを使ってGraphiteのデータを表示するダッシュボードを作る](http://www.ryuzee.com/contents/blog/6944)
[Grafana 公式](http://grafana.org/docs/)

# metrics収集ツール、Diamond
## Diamondとは
ここからが今回のメインです。
※以下では、「metrics」「データ」をあまり区別せず使います。metricsというのは例えばcpu usageとかload averageとか「測定される指標」のことであり、何らかの処理によって集められることによりデータになります。つまり正確には別ものですが、例えば「load averageがxxxだった」と言ったとき"load average" という指標なのかそれともデータそのものなのかを区別しないように、ここでもしないことにします。

[Diamond](https://github.com/BrightcoveOS/Diamond)
Diamond は、大きく２つのコンポーネントに分けられます

* collector
* handler

collectorは、データを収集する役目を果たします。収集するだけで、Diamondの外部に収集したデータを提供するというのとは違います。handlerは、収集したデータのハンドリングを行います。例えば、collectorで得られたデータをローカルのファイルに書きだしたり、Graphite(carbonといったほうがいいかも？)に送ったり、MySQLのテーブルに保存したり、異常があればアラート飛ばしたり、などなど。

また、Diamondはcollectorを定期的に実行するデーモンを提供しているので、自分でスケジューラを書く必要はありません。

## Diamondの強み
といいつつ、強みかどうかは微妙なのですが、Diamondはコミュニティにより提供されているcollectorの数がかなり多いです。
[Diamond/Collectors](https://github.com/BrightcoveOS/Diamond/wiki/Collectors)
各種system情報やapache, nginx, MySQL, PostgreSQL, Redis, MongoDBなんかの有名どころをはじめ、DRBDや、Openstack Swift なんかの比較的マニアックなmetricsまで集められます。

## とりあえず動かす
### インストール
基本的にはここ見ながらやります。pythonメインのプロジェクトなのにmakeを使ってビルドします。
[Diamond/Usage](https://github.com/BrightcoveOS/Diamond/wiki/Usage)

参考までに、インストールしたマシンのシステム情報。

    -(risuo@ebi)-(0)-
    -[9362]% cat /etc/lsb-release
    DISTRIB_ID=Ubuntu
    DISTRIB_RELEASE=12.10
    DISTRIB_CODENAME=quantal
    DISTRIB_DESCRIPTION="Ubuntu 12.10"
    -(risuo@ebi)-(0)-
    -[9369]% uname -a
    Linux ebi 3.5.0-23-generic #35-Ubuntu SMP Thu Jan 24 13:05:29 UTC 2013 i686 athlon i686 GNU/Linux

### 設定ファイル編集
最初は、diamond.confを編集します。
デフォルトではこんな感じ [Diamond / conf / diamond.conf.example](https://github.com/BrightcoveOS/Diamond/blob/master/conf/diamond.conf.example)
普通にインストールすると/etc/diamond/diamond.conf.example ができてるので、同じディレクトリにdiamond.conf という名前でコピーを作ります。

Graphiteにデータを送る場合、まずここを設定します

    [[GraphiteHandler]]
    ### Options for GraphiteHandler

    # Graphite server host
    host = graphite

    # Port to send metrics to
    port = 2003

    # Socket timeout (seconds)
    timeout = 15

    # Batch size for metrics
    batch = 1

hostの部分に、Graphiteサーバのホストを書きます。ポート番号は必要に応じて設定します。[server] セクションのhandlersにGraphiteが指定されている必要がありますが、デフォルトでそうなってるのでとりあえず意識する必要はありません。

以上、これだけでとりあえず動きます。

    sudo /etc/init.d/diamond start
    sudo service diamond start

などでデーモンを起動します。

しばらく待ってからGrafanaのダッシュボードを見ます。system情報がとれてるそれっぽいmetricsが選択できたら成功です。以下の画像では、cpu, diskspace, memory, iostat, load average 関連のmetricsを表示しています。

![grafana_2.png](https://qiita-image-store.s3.amazonaws.com/0/12053/91394de2-8b18-d76c-1faa-15a7a55c7339.png)

トラブルシューティングは/var/log/diamond/diamong.log とかみながらやると良いです。

## tips
### metricsの取得時間の間隔を設定したい
各種collectorのconfのinterval値を指定して起動します。diamond.conf でグローバルなデフォルト値を設定することも可能です。また、実はソースコードに埋め込むこともできます。get_default_configメソッドを読めば書き方はわかると思います。以下のページが詳しいです。
[Diamond/Configuration](https://github.com/BrightcoveOS/Diamond/wiki/Configuration)

こんな感じで書く(単位は秒)

    interval = 60

### loggerの設定をしたい
ログの出力形式やフォーマット、出力先なんかが指定できます。[Diamond/Configuration](https://github.com/BrightcoveOS/Diamond/wiki/Configuration)　を読めば大体わかります。

### handlerを設定したい
有効にしたいhandlerを、[server]セクションのhandlersで指定します。デフォルトだとGraphiteHandler,ArchiveHandlerが有効になってますが、こんな感じで指定されてます。

    handlers = diamond.handler.graphite.GraphiteHandler, diamond.handler.archive.ArchiveHandler

例えば、pickle化して送りたい場合は、GraphitePickleHandlerを[server]セクションで設定する必要があります。取得したデータをMySQLに保存したい場合はMySQLHandlerを指定します。

また、Influxdbに保存するhandlerであるInfluxdbHandlerもコミュニティにより提供されています。GrafanaはInfluxdbからも描画できるので好きな方を選ぶと良いです。

各種handlerの設定は、[handlers]セクションに記述します。

### カスタムcollector を開発したい
diamond.collector.Collectorを拡張する（普通にやるなら、派生クラスにする）ことで、カスタムcollectorを開発できます。diamond.collector.Collectorが持っているメソッドのうち、"publish"関連がcollectorとhandlerのインタフェースになってます。また、diamond.collector.Collectorは未実装の"collect"メソッドを持っていて、開発者は派生クラスでcollectを実装することになります。以下のページが参考になります。
[Diamond/CustomCollectors](https://github.com/BrightcoveOS/Diamond/wiki/CustomCollectors)

ただ、これだけだと情報量が少ないので、カスタムcollectorを開発するならCollectorクラスの実装を読んでおいたほうがいいと思います。
[collector.py](https://github.com/BrightcoveOS/Diamond/blob/master/src/diamond/collector.py)

例えば、publishメソッドにはprecisionという引数があって、metricsの有効数字の桁数を指定しています。これがデフォルトでは0になっている、つまり整数しか扱えない設定になってます。metricsをfloatで扱いたい場面は結構多いはずですが、ソースコードを読まないと解決策がわからない、みたいな状態のようです。

## 類似のソリューション
sensuとfluentdなどは似たようなことができるイメージです。
[sensu](http://sensuapp.org/)
[fluentd](http://www.fluentd.org/)

ざっとググってみた感じ、sensuはmetrics収集以外にも色々できるようです。sensu APIを使ってsensu clientが入ってる各ノード情報を出力するダッシュボードが作れたりするのかっこいいですね。これはDiamondだと真似できなそうです。以下のサイトが参考になります。
[Graphite と Sensu について](http://qiita.com/inokappa/items/d93ac42f00f117ba4894)
[Sensuを使って自由度の高い監視システムの構築を行う方法](http://www.ryuzee.com/contents/blog/6843)
[Fluentd を使って CloudWatch のメトリクスを Graphite で見れるようにする](http://qiita.com/inokappa/items/ee993b14f82e544ca6e4)
[InfluxDB と fluentd を組み合わせを試してみた](http://qiita.com/hakobera/items/fbe7669a1c2b763bcd8d)

# まとめ・感想
簡単にですが、Diamondについて書いてみました。データを見えるようにしておくのは重要なので、今後もこういったツールは押さえておくといい気がしてます。