はじめに
以前に記載した cactiの過去グラフが平均化されないようにする方法 では、デフォルトのDataProfileを利用すると、過去データが平均化されれしまい、過去に遡って詳しい情報が見れなくなってしまう、という対策のために行いました。
ですが、データソースあたりのファイル容量が大きくなってしまうため、なんとかしたかったので、その対策を行いました。
備忘録としてまとめます。
結局なにをしたんだっけ?
対象機器および環境
- RRDtool (1.7.0)
- cacti (バージョンには依存せず)
現状の問題点
前回のエントリで作成したDataProfile
過去のデータを平均化させず、5分毎の取得値をそのまま1.5年間閲覧可能なようにRRAの解像度を高く設定しています。
このDataProfileでは、ひとつのデータソース(以下、DS)に対して、AVERAGE、MIN、MAX、LASTの4つのCF(Consolidation Functions)が定義されており、それぞれのCFに対して、Daily、Weekly、Monthly、Yearlyの4種類のRRA定義を対応させています。
そのため、1データソースあたり6MByte程度必要となり、グラフあたりの関連データソース数が多いものや、ポート数の多いネットワーク機器などが大量にある場合には、データ量がハンパない状態になってしまいます。
たとえば、48ポートのスイッチの場合、
トラフィックを取得する場合のデータソースはtraffic_in
とtraffic_out
の2つ
エラーを取得する場合のデータソースは
discards_in
とdiscards_out
とerrors_in
とerros_out
の4つ
これらを合算すると、48(port) * 6(DS) * 6MByte = 1728MByte
スイッチ1台あたり2GByte弱(!) も食ってしまいます。
業務で使おうもんなら、1ラックで100GBとかいっちゃうんじゃないか、これ。
デフォルトで用意されているDataProfile
デフォルトは、1DSあたり92Kbyteなので、48ポートスイッチでも、 30MByte弱と、約1/60 です。おさいふに優しい。
ですが、以下のようにデータが平均化されます。
|参照期間|データ粒度|
|:-:|:-:|:-:|
|現在~2日前まで|5分毎の取得値の値そのまま|
|~2週間前まで|5分毎の取得値の30分平均|
|~2か月前まで|5分毎の取得値の2時間平均|
|~2年前まで|5分毎の取得値の1日平均|
つまり、2か月より前のデータと参照しようとすると、解像度の低いRRAに保管されている1日につき1つのデータしか参照できません。
3か月前のイベントの時のトラフィックってどうだったっけ?と、その日を抽出して見ようとすると、1日のグラフが長方形になり、なんのこっちゃ状態です。
で、どうするか
cactiは取得値をそのまま使うよりも、「つい最近どうだったか」を見る意味合いが強いと思いますし、過去情報はトレンドが確認できればよいともとらえることができますので、デフォルト設定もしかたなしと思います。
(プリセットのDataProfileでは30秒ごとの取得とかもありますしね。。。)
でも、過去のデータもそのまま参照したい、でもデータ量がこんなになるのは許せない。
ということで、対策を考えることにしました。
解決方法
実はこれ、グラフテンプレートのGPRINTで記載されたCFはRRAで設定したCFじゃなさそうだ、と気づいたことがキッカケでした。
つまり、 グラフ作成で参照されないCFは消しちゃえばいいんじゃね? ということです。
仮説と検証
グラフテンプレートを確認して、不要なCFとRRAを削除しても問題ないかどうかを確認していきます。
一般のご家庭での利用なので、このくらいです。
解説が簡単なCPUを2種類取り上げます
GT - CPU Usage Cisco
これはCiscoデバイス用のCPU利用率のグラフを作成するための、グラフテンプレート
設定は以下のようなものです。
グラフの右上にある歯車マーク → スパナマークとクリックしていくと、RRDtoolのグラフ生成コマンドが確認できます。
/bin/rrdtool graph - \
--imgformat=PNG \
--start='1579556940' \
--end='1579719840' \
~(省略)~
DEF:a='/usr/share/cacti/rra/rhq01_5min_cpu_38.rrd':'5min_cpu':AVERAGE \
AREA:a#FF0000FF:'CPU Usage' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n'
RRDtool Command lengths = 924 charaters.
RRDtool Says:
OK
このうち、DEF:~~
の部分が、グラフを作成する元データとなる、「RRDファイル」「DS」「CF」を指定しています。
ここは元データなるので、RRDファイルから削除してはいけません。
GPRINT:~~
にもCFがLAST/AVERAGE/MAXが記載されていますが、これはRRDファイルのデータが使われているのでしょうか?
RRDファイルのデータを参照していないようであれば、削除できますね。確認してみます。
元データからグラフを作成
先ほどのグラフ作成のコマンドを最小限のものに切り出して、グラフを作成してみましょう。
// グラフを作成する。
$ cp /usr/share/cacti/rra/rhq01_5min_cpu_38.rrd ./origin.rrd
$ /bin/rrdtool graph - --imgformat=PNG \
--start='1579556940' --end='1579719840' \
DEF:a='./origin.rrd':'5min_cpu':AVERAGE \
AREA:a#FF0000FF:'CPU Usage' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
> origin.png
// ハッシュを確認
$ md5sum origin.png
a72f5bc258a088443209eb9a0db0c54d origin.png
参照されていないCFを削除したRRDデータからグラフを作成
RRDファイルの複製からAVERAGE以外を削除して同一のグラフが生成されるか確認します。
// 元のRRDファイルをコピーし、AVERAGE以外のCFのインデックスを探します。
$ cp /usr/share/cacti/rra/rhq01_5min_cpu_38.rrd ./check.rrd
$ rrdtool info check.rrd | grep 'MIN\|MAX\|LAST'
rra[4].cf = "MIN"
rra[5].cf = "MIN"
rra[6].cf = "MIN"
rra[7].cf = "MIN"
rra[8].cf = "MAX"
rra[9].cf = "MAX"
rra[10].cf = "MAX"
rra[11].cf = "MAX"
rra[12].cf = "LAST"
rra[13].cf = "LAST"
rra[14].cf = "LAST"
rra[15].cf = "LAST"
// RRAの4-15を削除すれば、AVERAGEのみが残ります。
$ rrdtool tune check.rrd DELRRA:4 DELRRA:5 DELRRA:6 \
DELRRA:7 DELRRA:8 DELRRA:9 DELRRA:10 DELRRA:11 \
DELRRA:12 DELRRA:13 DELRRA:14 DELRRA:15
// AVE以外のCFを削除したRRDファイルからグラフを作成する。
$ /bin/rrdtool graph - --imgformat=PNG \
--start='1579556940' --end='1579719840' \
DEF:a='./check.rrd':'5min_cpu':AVERAGE \
AREA:a#FF0000FF:'CPU Usage' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
> check.png
// ハッシュを確認
$ md5sum check.png
a72f5bc258a088443209eb9a0db0c54d check.png
同一であることが確認できました。では、AVERAGE以外のCFは削除できそうですね。
解像度の低いRRAを削除したRRDデータからグラフを作成
次に、解像度が低いRRAを削除して、もとのグラフと同一のものが生成できるか確認します。
(解像度が最も高いものは、STEPが1なので、rra[x].pdp_per_row = 1
なのですが、わかりやすいように、cactiで設定したときの rra[x].rows = 157680
を用いています)
// RRAの解像度の最も高いものを探して、それ以外を削除します。
$ rrdtool info check.rrd | grep 'rows'
rra[0].rows = 547
rra[1].rows = 157680 ←これ以外を削除
rra[2].rows = 6570
rra[3].rows = 26280
// RRAの0,2,3を削除すれば、必要なデータのみが残ります。
$ rrdtool tune check.rrd DELRRA:0 DELRRA:2 DELRRA:3
// 不要なデータを削除したRRDファイルからグラフを作成する。
$ /bin/rrdtool graph - --imgformat=PNG \
--start='1579556940' --end='1579719840' \
DEF:a='./check.rrd':'5min_cpu':AVERAGE \
AREA:a#FF0000FF:'CPU Usage' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
> check2.png
// ハッシュを確認
$ md5sum check2.png
04cff82bb092918e896622d2b8724eeb check2.png
あら、 ダメでした ね。
なぜダメだったか
元データと、ダメデータの双方のデータと、期間を絞って見てみましょう。
// 元のデータ
$ rrdtool fetch origin.rrd AVERAGE --start='1579673900' --end='1579675000'
5min_cpu
1579674000: 4.0000000000e+00
1579674300: 4.9966666667e+00
1579674600: 5.9966666667e+00
1579674900: 5.0233333333e+00
1579675200: 5.0000000000e+00
// RRAを削除したデータ
$ rrdtool fetch check.rrd AVERAGE --start='1579673900' --end='1579675000'
5min_cpu
1579674000: 6.9800000000e+00
1579674300: 7.0000000000e+00
1579674600: 7.0000000000e+00
1579674900: 7.0000000000e+00
1579675200: 7.0000000000e+00
なんか欲しいデータじゃないですね。
データの状態から推測すると、インデックス0番目を削除するときに、1番目のデータが0番目にコピーされてから、0番目の領域が拡張されているような感じです。つまり、0番目の領域にコピーされた時点で平均化されてしまうようですね。 (ちゃんと調べてません)
ひとまず、0番目を詰めなければ大丈夫そうですね。
// 元RRDファイルからRRAの2-15を削除します。
$ cp origin.rrd check2.rrd
$ rrdtool tune check2.rrd DELRRA:2 DELRRA:3 DELRRA:4 DELRRA:5 DELRRA:6 \
DELRRA:7 DELRRA:8 DELRRA:9 DELRRA:10 DELRRA:11 \
DELRRA:12 DELRRA:13 DELRRA:14 DELRRA:15
// グラフを作成する。
$ /bin/rrdtool graph - --imgformat=PNG \
--start='1579556940' --end='1579719840' \
DEF:a='./check2.rrd':'5min_cpu':AVERAGE \
AREA:a#FF0000FF:'CPU Usage' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
> check2.png
// ハッシュを確認
$ md5sum check2.png
a72f5bc258a088443209eb9a0db0c54d check2.png
OKでした。
つまり、このグラフテンプレートでは、AVERAGE以外のCFは参照されていないことがわかりました。
同様にもう一つのグラフテンプレートで検証してみましょう。
GT - CPU Usage Windows/Linux
これはWindowsやLinuxのCPU利用率のグラフを作成するための、グラフテンプレート
先ほどと同様に確認してみます。
元データからグラフを作成
/bin/rrdtool graph - \
--imgformat=PNG \
--start='1553520300' \
--end='1554887940' \
~(省略)~
DEF:a='/usr/share/cacti/rra/esxi01_cpu_118.rrd':'cpu':AVERAGE \
DEF:b='/usr/share/cacti/rra/esxi01_cpu_118.rrd':'cpu':MAX \
AREA:a#FF00007F:'CPU Utilization' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
LINE1:b#FF0000FF:
これは、DEFにCFのMAXが使われてしまっていますね。
参照されているCFも削除しRRDデータからグラフを作成
でも、考えてみると、5分毎の値を常時保管できているので、MAXの値は(に限らず、他の値も)実は利用していないのでは?
$ rrdtool tune check.rrd DELRRA:3 DELRRA:4 DELRRA:5 DELRRA:6 \
DELRRA:7 DELRRA:8 DELRRA:9 DELRRA:10 DELRRA:11 \
DELRRA:12 DELRRA:13 DELRRA:14 DELRRA:15
$ cp check.rrd /usr/share/cacti/rra/esxi01_cpu_118.rrd
ピークは無くなっていますが、AREAの部分はほぼ同じ。表示されるMaximumの数値も55で同じですね。
ちなみに、このときのグラフ作成コマンドは以下になっていました。
/bin/rrdtool graph - \
--imgformat=PNG \
--start='1553520300' \
--end='1554887940' \
~(省略)~
DEF:a='/usr/share/cacti/rra/esxi01_cpu_118.rrd':'cpu':AVERAGE \
AREA:a#FF00007F:'CPU Utilization' \
GPRINT:a:LAST:'Current\:%8.0lf' \
GPRINT:a:AVERAGE:'Average\:%8.0lf' \
GPRINT:a:MAX:'Maximum\:%8.0lf\n' \
LINE1:a#FF0000FF:
CFのMAXがないので、自動的にコマンドを削除してくれているようです。親切。
そのままだと、rrdtoolのエラーでグラフが生成されないのでしょう。
GPRINT:a:MAX:'Maximum\:%8.0lf\n'
が同じなため、数値の表示は55なのですね。
5分毎のデータは保管されているはずなので、拡大したら同じはずです。
見てみましょう。
これは、同一といってよいですね。
まぁ、グラフテンプレートの作り方といえばそれまでなので。
検証結果
CFの削除について、
グラフテンプレートで利用されていないCFは削除しても大丈夫。
グラフテンプレートで利用されていても、参照先のCFが無ければ、自動的に除外され、エラーにはならない。
同一CFの解像度の異なるインデックスの削除について
最も解像度の高いRRAが残っていれば大丈夫。
それ以外を削除しても大丈夫だが、当該のRRAインデックスよりも小さなものは削除してはいけない。
実装
前述の検証結果に基づいて、グラフテンプレートに利用されていないCFを削除する。
調査の結果、自身の環境では、先ほどのWindows/LinuxのCPU利用率以外はすべてAVERAGEのみだった。
CPU利用率の過去グラフでMAX値はあまり必要ないので、AVERAGE以外はすべて削除してしまうことにする。
トラブル時でも調査だとしても、CPU利用率の参照は、せいぜい1週間くらいと思われる。
まぁ、あったらあったで、グラフ見てニヤニヤできる楽しさは残せるんだけど。
perlでスクリプトを作成
#!/bin/perl
# 今回の保管対象は CF:AVERAGEでROWS:157680
# もともとのDataProfileではCFが4種、RRAが4種だったので、インデックスは0-15までで決め打ちしちゃう
$target_cf = "AVERAGE";
$target_rows = 157680;
$index_max = 15;
foreach $file (glob("./*.rrd")){
# rrdtool info を実施し、保管対象のCFとROWSをgrepしておく
$cmd = "rrdtool info $file | grep 'cf\\ =\\ \\\"$target_cf\\\"\\|rows\\ =\\ $target_rows' ";
undef(%flg_cf); # CFのチェック用フラグ
foreach(split(/\n/,`$cmd`)){
# まずCFをチェックして当該のインデックス値を保管しておく
if($_ =~ /\[(\d+)\]\.cf\ =\ \"$target_cf\"/){
$flg_cf{$1} = 1;
}
# まずROWSをチェックして当該のCFと同一のインデックス値だったら、それが保管対象のインデックスになる
if($_ =~ /\[(\d+)\]\.rows\ =\ $target_rows/){
$check_index = $1;
if($flg_cf{$check_index}){
last;
}
}
}
# 当該インデックスより小さなものは削除できないので、当該インデックスの次から最後まで削除する
$cmd = "rrdtool tune $file ";
foreach (($check_index+1)..$index_max){
if($_ ne $check_index){
$cmd .= "DELRRA:$_ ";
}
}
# テスト用表示
#print $cmd."\n";
system($cmd);
}
exit;
確認する
// 自身の環境では、RRDファイルは174個ありました。
$ ls -1 | nl | tail -n1
174 vmwlc01_traffic_in_297.rrd
// データサイズは2.5G
$ du -hs
2.5G ./
$ ./redrra.pl
// データサイズは571MBに削減
$ du -hs ./
571M ./
データサイズは2.5GB → 571MBとなり、1/5程度となりました。
あ、もちろんバックアップはとりましたよ。
あと、実施後は、RRDファイルのパーミッションがapacheから読み書きできる状態であるか、確認しておきます。
うーん、つまんねぇグラフだな
スクリーンショットのタイミングでデータ更新されたため、すこーしピーク場所などが変わっていますが、
Windows/LinuxのCPU負荷のグラフ以外はほとんど見た目は変わっていません。
おしまい
あとしまつ
ログも特にエラーは出ていないようです。
DataProfileの作成
AVEのみ5分毎の値を1.5年間保管する、というプロファイルを作成し、デフォルトに設定します。
いままでは1データソースあたり約6MByteでしたが、修正後は約1.2MByteになりました。
cactiでの定義との乖離
Console -> Management -> Datasourceからデバッグ情報をみると、さっき作ったDataProfileで作成されたことになってて(ほんとは違うのに)、知らないインデックスがあるぞ、と言われていますが、まぁ大丈夫でしょう。
さいごに
インデックスを0まで詰めたかったので、 rrdtool resize check_last.rrd 0 GROW 157133
からのrrdtool tune resize.rrd DELRRA:0
とかやってみたけど、ダメでした。
たぶん ダンプの結果を新規作成したRRDに突っ込めばいけるとは思うのですが、なんか力業すぎてちょっと避けました。
あと、rrdtoolの機能すごい。とcactiの機能すごい。全然つかいこなせませんわ。
出典