Y-Ken Studio

新しもの好きのデータエンジニアが四方山話をお届けします。

サーバ監視ツール「Munin」のiowaitを劇的に減らす方法

10分ほどあれば設置できる程にお手軽な「Munin」というサーバ監視ソフトを使い始めて早数ヶ月。様々な計測値がグラフ形式で一望出来るので、問題の早期発見が出来るようになり、とても重宝しています。


ただ、MuninはNagiosなどと違い、ログの保存だけではなく同時にグラフの更新も行っています。これに加えて各サーバから取得したデータのグラフ化をcronで5分おきに行っているので、常時Muninサーバへ負荷が掛かっている状態です。
現在、既に監視対象が40台を超え、Muninが動くサーバのIO負荷が高いのが気になってきました。


どのようにMuninのDisk I/O Waitを減らすか調べても、特に情報がありません。
そこで、Muninの処理を追う事で、軽量化の方法を探ろうと思います。


結論から言うとCPUのコア数は重要ではなく、メモリを十分に載せる必要があります。

環境

必要とされるメモリ量を求める方法

  • /etc/munin/munin.conf にある、dbdirとhtmldirのパスを確認。

今回はデフォルトのまま使っていたと仮定して進めます。

dbdir	/var/lib/munin
htmldir /var/www/html/munin
  • それぞれの使用容量をduコマンドを使って確認

これらを合計した量が、グラフで見る実際の使用量に加えて必要な量です。
600MB+597MB=1197MBに加えて、OS等が使っている200〜300MBが最低限必要という事になります。*1

$ du -h -s /var/lib/munin
600M	/var/lib/munin
$ du -h -s /var/www/html/munin
597M	/var/www/html/munin

先程の計算を元にサーバのメモリ量を変更

今回はLinux KVMの仮想環境だったので、virt-managerでメモリの割り当てを
余裕を持って1GBから2GBに変更した所、白く分断している所を境に、改善が見られました。

使えるメモリが増えた事で、I/O waitが減った事が明らかに分かると思います。
方法論としては以上ですが、ここからさらに掘り下げていきます。



なぜ生データやhtml領域分のメモリを過剰に割り当てる必要があるのか?

よく使うデータをページキャッシュに載せておくと、ディスクアクセスが削減出来るという仕組みを使っています。
以下にグラフ生成の流れを踏まえて解説します。

グラフを生成する際の流れ

  1. 各サーバからデータ収集を行い、dbdirへRRD-Tool形式で書き出す
  2. RRD-Toolから書き出された生データをmunin-graphというプロセスが読み出し、グラフをhtmldirへ書き出す
  3. munin-htmlというプロセスが既に書き出されたグラフ画像を1つ1つ全て読み込んで、画像の幅や高さを取得し、そのデータも使いながらテンプレートを元にHTMLを生成する

RRD-Toolから書き出されたファイルと、書き出されたグラフのpngデータがページキャッシュに載る事で、ディスクへの読み込み処理がほとんどなくなり、上記のようなiowaitが綺麗に無くなるという次第です。

ちなみに、試しにHTML領域の所(htmldir)だけをRAMディスク(/dev/shm/)に載せてみた所、iowaitは最後のHTML生成処理だけ下がりました。この方法は意図せぬハングアップでデータが消える危険な置き方なので、常用は避けた方が良いですね。

まとめ

このまま100台規模にMuninの監視対象を拡張していくと、大量のメモリが必要になってしまいます。*2
ある程度の規模になったところで、仮想ではなく重たくなっても支障のない適当なMunin専用サーバを用意する事や、大規模環境でも問題なく稼働するCactiなどに時間を掛けて乗り換えていくと良いと思います。


【おまけTips】MuninのCron周期を変更したい場合

/etc/cron.d/munin の中の以下の行をcrontabの記述ルールに従って編集して下さい。
例えば10分おきにしたい場合には、「*/5」を「*/10」にする事で出来ます。

*/5 * * * *     munin test -x /usr/bin/munin-cron && /usr/bin/munin-cron 

【おまけTips】CPUのコア数はどれほど必要なのか?

以下、Muninの定期処理にどれだけの時間が掛かったかのグラフです。
実験的に8コア割り当てていた事もあり、上にあるCPUのグラフでは最大800%になっていましたが、そんな数は全く不要です。
速く動かしたいならCPU割り当てを増やすのではなく、何よりまずはメモリを積んで下さい。
正直、Munin専用ならCPUコア数が1つや2つでも良いと思いますが、他システムと同居させるなら、2コア以上を推奨します。
ちなみに当環境では、8コアから4コアに変更しても、グラフ生成の時間に全く変化はありませんでした。


※ 監視項目と対象サーバ数によって変わるので、上記のグラフでアラートにならない程度であれば問題ないです。

【おまけTips】CPUの負荷を減らしたい場合

グラフ生成の並列実行数(max_graph_jobs)を調整するとCPUの負担が減らせます。
ただ、これを減らすと処理時間が延びるので、バランスを見て調節しましょう。

【おまけTips】pngファイルから幅や高さを取得する事を無効化する為のヒント

img srcにwidth,heightを記述する事によって、ページ表示時に、ブラウザ側のレンダリング効率が良くなります。
しかしそれ以上にサーバに負荷が掛かるのであれば、あえて無効化するというのも1つの手法です。
無効化するためのヒントを以下に記載します。


例えば "/etc/munin/templates/munin-comparison-day.tmpl" というテンプレートでは、IMGDAYWIDTHとIMGDAYHEIGHTという値を読み込んでいます。
munin-htmlの中をのぞくと、Perlのプログラムとなっており、Munin::Master::HTMLOldを呼び出している事が分かります。
という事から、CPANのmoduleがインストールされているディレクトリにある以下のファイルを変更すれば出来ますね。
/usr/lib/perl5/vendor_perl/5.8.8/Munin/Master/HTMLOld.pm


このプログラムでは、以下箇所でget_png_sizeというメソッドを使い、pngファイルを開いて幅や高さを取得しています。
ここをコメントアウトなり違い処理に書き換えれば、期待する動作になるのではないでしょうか。

    for my $scale (@times) {
        if (my ($w, $h)
            = get_png_size(munin_get_picture_filename($service, $scale))) {
            $srv{"img" . $scale . "width"}  = $w;
            $srv{"img" . $scale . "height"} = $h;
        }
    }
    if (munin_get_bool($service, "graph_sums", 0)) {
        $srv{imgweeksum} = "$srv{node}-week-sum.png";
        $srv{imgyearsum} = "$srv{node}-year-sum.png";
        for my $scale (["week", "year"]) {
            if (my ($w, $h)
                = get_png_size(munin_get_picture_filename($service, $scale, 1)))
            {
                $srv{"img" . $scale . "sumwidth"}  = $w;
                $srv{"img" . $scale . "sumheight"} = $h;
            }        }
    }

【おまけTips】PNG画像を小さくする事によるメモリ節約

pngの出力形式は通常、24bitカラーとなっているので、8bitカラーとしての書き出しにすれば、容量は1/3以下になります。
容量が少なくなるという事は、ブラウザでの読み込みが速くなるほか、Linuxのページキャッシュを節約する事も出来ます。
変更方法は調べておりませんが、munin-graphを解析すれば出来るのではないでしょうか。

*1:正確にはこの中のpngファイルの容量です。htmlファイルの容量は微々たる量なので気にしていません。

*2:pngファイルを開いて高さを取得するという処理をスキップするようにmuninを書き換えれば、Cacti+α程度の要求スペックになります。すなわち、RRD-Toolの書き出すファイル容量分だけページキャッシュに乗るようにすれば、そこまでの容量のメモリは必要としないという事です