Cacti の thold プラグインでアラートを仕込むのがめんどくさくて仕方なかったので、もういっそのこと直接 rra ファイルを見てアラートを出すスクリプトを自前で作れば良いんじゃないかと思ったときのメモ。
Cacti のバージョンは 0.8.8h です。
Prometheus に入門したので中途半端なままで放置。
rra ファイルのパスは cacti の DB から下記のような SQL で取ります。
SELECT host.id as host_id, host.description as host_description, data_template.name as data_template_name, data_template_rrd.data_source_name as data_source_name, poller_item.rrd_path as rrd_path FROM data_local INNER JOIN host ON data_local.host_id = host.id INNER JOIN data_template ON data_local.data_template_id = data_template.id INNER JOIN data_template_rrd ON data_local.id = data_template_rrd.local_data_id AND data_local.data_template_id = data_template_rrd.data_template_id INNER JOIN poller_item ON data_local.id = poller_item.local_data_id
メトリクスの値は rrdtool で下記のように取れます。
rrdtool fetch hoge_prod_ap01_load_1min_100.rrd MAX \ -s $(( $(date +%s) - 3600 )) -e $(( $(date +%s) - 300 ))
load_1min 1490619600: 7.0000000000e-02 1490619900: 8.6600000000e-02 1490620200: 6.4900000000e-02 1490620500: 2.6266666667e-02 1490620800: 3.3333333333e-03 1490621100: 6.6933333333e-02 1490621400: 7.1633333333e-02 1490621700: 8.6400000000e-02 1490622000: 9.0000000000e-02 1490622300: 1.5533333333e-01 1490622600: 5.7533333333e-02 1490622900: 3.0000000000e-02
あるいは xport なら複数の rra から JSON で取得できるので、こっちのが良さそう。
rrdtool xport --json \ -s $(( $(date +%s) - 3600 )) -e $(( $(date +%s) - 300 )) \ DEF:mem_buffers=hoge_prod_ap01_mem_buffers_101.rrd:mem_buffers:MAX \ DEF:mem_cache=hoge_prod_ap01_mem_cache_102.rrd:mem_cache:MAX \ DEF:mem_free=hoge_prod_ap01_mem_free_103.rrd:mem_free:MAX \ DEF:mem_total=hoge_prod_ap01_mem_total_104.rrd:mem_total:MAX \ XPORT:mem_buffers:mem_buffers \ XPORT:mem_cache:mem_cache \ XPORT:mem_free:mem_free \ XPORT:mem_total:mem_total
{ about: 'RRDtool xport JSON output',
meta: {
"start": 1490619900,
"step": 300,
"end": 1490619900,
"legend": [
'mem_buffers',
'mem_cache',
'mem_free',
'mem_total'
]
},
"data": [
[ 8.5200000000e+02, 1.9999189200e+06, 7.8921592000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0017213467e+06, 7.8882005333e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0034699067e+06, 7.8495132000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0018100000e+06, 7.8899000000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0028664133e+06, 7.8575062667e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0050689867e+06, 7.8603305333e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0068675200e+06, 7.8260720000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0052690000e+06, 7.8560060000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0062675333e+06, 7.8268226667e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0079922267e+06, 7.8281285333e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0063401600e+06, 7.8266224000e+05, 3.8821600000e+06 ],
[ 8.5200000000e+02, 2.0078709467e+06, 7.8317032000e+05, 3.8821600000e+06 ]
]
}
がしかし、これよく見たら JSON としては invalid ですね。。。--json を指定しなければ XML なのでそっちの方が良いかも。
あとは・・・
- ホスト名は
host.descriptionに対して正規表現でパターンで指定する- それっぽく
descriptionが設定されている前提 <service>-<env>-<role><num>みたいに
- それっぽく
data_source_nameだけではメトリクスを一意に特定できないことがあるのでデータテンプレートも指定する- データテンプレートは名前でしか識別できなさそうなのでエイリアスを正規表現で指定する
- 実際の閾値設定ではエイリアス名で指定する
data_source_nameだけで一意になるなら監視設定ではデータテンプレートのエイリアスは省略しても良い
- メトリクスをコールバックで加工した値に閾値を設定する
例えば下記のように設定する。
return [
// データテンプレートのエイリアス
// 複数のデータテンプレートがマッチするがデータソース名と足して一意になる前提
'alias_data_template' => [
'memory' => '^ucd/net - Memory -',
],
'alert' => [
[
// ホスト名のパターン
'host' => '^hoge-prod-ap\d+$',
// データテンプレートのエイリアス+データソースのリスト
'ds' => [
'memory:mem_total',
'memory:mem_buffers',
'memory:mem_cache',
'memory:mem_free',
],
// チェックする値、引数の並びは ds に対応
'expr' => function ($total, $buffer, $cache, $free) {
return ($total - $buffer - $cache - $free) / $total * 100;
},
// 閾値
'threshold' => [
'WARNING' => 80,
'CRITICAL' => 90,
],
// 通知先
'notify' => [
'WARNING' => ['ore@example.com', 'are@example.com'],
'CRITICAL' => 'sore@example.com',
],
// 通知のメッセージ
'message' => '{severity} [{hostname}] memory usage too high ... now:{value} > {threshold}',
],
],
];
なにかしらスクリプトを実行することで、DB を舐めてホスト名やデータテンプレート名のパターンとデータソースに基づく rra のパスをキャッシュしておくことで、定期的な閾値のチェック処理を軽減する。
例えば下記のようなキャッシュになるだろうか。
return [
'host_ids' => [
// パターンに対するホストIDの一覧
'^hoge-prod-ap\d+$' => [1, 2, 3, 4],
],
'rra_paths' => [
// ホストID => データテンプレート+データソース => RRA
1 => [
'memory:mem_total' => '/path/to/rra/are_prod_ap01_mem_total_1.rra',
'memory:mem_buffers' => '/path/to/rra/are_prod_ap01_mem_buffers_2.rra',
'memory:mem_cache' => '/path/to/rra/are_prod_ap01_mem_cache_3.rra',
'memory:mem_free' => '/path/to/rra/are_prod_ap01_mem_free_4.rra',
],
],
];
Prometheus を使ってみた感じ、さくさく設定できてもうこれでいいかなと思ったので、この案はお蔵入り。