ZabbixでMuninのMemoryグラフを再現する

Zabbixはメモリ監視がMuninより苦手です。デフォルトのLinuxテンプレートはあまり役に立ちません。ここはひとつ気合いである程度まで再現してみましょう。

お手本となるMuninのMemoryグラフ

まずはMuninのグラフを確認します。
memory-day
この中でも重要と思われるapps ~ swap(塗りつぶしグラフ)をZabbixで再現します。というかZabbix2.Xは塗りつぶしグラフと線グラフの共存ができません。

これらの値は、基本的に/proc/meminfoの値を参照すれば取得できるのですが「apps」と「swap」は自分で計算する必要があります。そうなると/etc/zabbix/zabbix_agentd.confにUserParameterを1行追加するだけでは実現できませんので、スクリプトを作成する必要が出てきました。

Memory取得スクリプトを作成する

appsとswapはmuninグラフの読み方と意味 | シーズクリエイターズブログによると以下のの計算式で求められるとのことです。

「apps」
 = MemTotal - MemFree - Buffers - Cached - Slab - PageTables - SwapCached

「swap」
 = cache - (SwapCache + buffers)

※参考 muninmuninグラフの読み方と意味 | シーズクリエイターズブログ
 https://www.seeds-std.co.jp/seedsblog/488.html

まずは確実に動作するスクリプトとしてこんなものを作ってみます。

# vi /etc/zabbix/zabbix.memory.sh
#!/bin/sh

## /proc/meminfoから計算に必要な値を取り出す
MemTotal=$(cat /proc/meminfo |grep MemTotal| awk '{print $2}')
MemFree=$(cat /proc/meminfo |grep MemFree| awk '{print $2}')
Buffers=$(cat /proc/meminfo |grep Buffers| awk '{print $2}')
Cached=$(cat /proc/meminfo |grep Cached| awk '{print $2}' |head -n1)
Slab=$(cat /proc/meminfo |grep Slab| awk '{print $2}')
PageTables=$(cat /proc/meminfo |grep PageTables| awk '{print $2}')
SwapCached=$(cat /proc/meminfo |grep SwapCached| awk '{print $2}')
SwapTotal=$(cat /proc/meminfo |grep SwapTotal| awk '{print $2}')
SwapFree=$(cat /proc/meminfo |grep SwapFree| awk '{print $2}')

## meminfoの単位がKBなので、1024をかけてB表記にする。
## appsとswapは値を計算する
apps=$(expr \( $MemTotal - $MemFree - $Buffers - $Cached - $Slab - $PageTables - $SwapCached \) \* 1024)
page_tables=$( expr $PageTables \* 1024)
swap_cache=$( expr $SwapCached \* 1024)
slab_cache=$( expr $Slab \* 1024)
cache=$( expr $Cached \* 1024)
buffers=$( expr $Buffers \* 1024)
unused=$( expr $MemFree \* 1024)
swap=$( expr \( $SwapTotal - $SwapFree \) \* 1024)

## 判別しやすいようにヘッダを付けて計算結果を出力する
echo apps. $apps
echo page_tables. $page_tables
echo swap_cache. $swap_cache
echo slab_cache. $slab_cache
echo cached. $cache
echo buffers. $buffers
echo unused. $unused
echo swapd. $swap

exit

このスクリプトに実行権を付与して処理を行ってみます。

# chmod 755 /etc/zabbix/zabbix.memory.sh
# ll /etc/zabbix/zabbix.memory.sh
-rwxr-xr-x 1 root root 1148  7月 31 19:46 2016 /etc/zabbix/zabbix.memory.sh
# /etc/zabbix/zabbix.memory.sh
apps. 514482176
page_tables. 33808384
swap_cache. 165908480
slab_cache. 65183744
cached. 970907648
buffers. 120242176
unused. 97595392
swapd. 758263808

とりあえずこれで必要な値を出力できるようになりましたがこのスクリプトは2つ問題があります。
1つは/proc/meminfoを9発も打っているので無駄な処理が多く遅いこと、もう1つは1発1発毎に/proc/meminfoの結果が異なるので厳密には正確な値でないこと。この二つを解決できる方法を思いついたので修正してみました。

Memory取得スクリプトを改良する

/proc/meminfoの実行を1回で済ますことができれば、2つの問題は解決します。

まずは/proc/meminfoから処理に必要な行をgrepの|(または)を使って取り出します。

# cat /proc/meminfo |grep "\(MemTotal:\|MemFree:\|Buffers:\|Cached:\|Slab:\|PageTables:\|SwapCached:\|SwapTotal:\|SwapFree:\)"
MemTotal:        1922000 kB
MemFree:           96736 kB
Buffers:          117672 kB
Cached:           948532 kB
SwapCached:       162020 kB
SwapTotal:       4128764 kB
SwapFree:        3388272 kB
Slab:              63604 kB
PageTables:        32724 kB

次に「awk ‘{print $2}’」を使って2列目だけを取り出し、「tr ‘\n’ ‘,’」で改行を区切り文字「,」に置換します。

# cat /proc/meminfo |grep "\(MemTotal:\|MemFree:\|Buffers:\|Cached:\|Slab:\|PageTables:\|SwapCached:\|SwapTotal:\|SwapFree:\)" | awk '{print $2}'|tr '\n' ','
1922000,93316,117964,950812,162020,4128764,3388272,63880,32848,

この出力結果を変数「TEXT」に格納、「IFS=’,’」で区切り文字「,」を指定し、「set — $TEXT」でTEXTの文字列を配列に配置します。

# TEXT=$(cat /proc/meminfo |grep "\(MemTotal:\|MemFree:\|Buffers:\|Cached:\|Slab:\|PageTables:\|SwapCached:\|SwapTotal:\|SwapFree:\)" | awk '{print $2}'|tr '\n' ',')

# IFS=','
# set -- $TEXT

# echo $1 $2 $3 $4 $5 $6 $7 $8 $9
1922000 93316 117964 950812 162020 4128764 3388272 63880 32848

$1 ~ $9の結果を変数に代入する

# MemTotal=$1
# MemFree=$2
# Buffers=$3
# Cached=$4
# Slab=$8
# PageTables=$9
# SwapCached=$5
# SwapTotal=$6
# SwapFree=$7

この後の処理は改良前と同じですので、結果的にこうなります。

# /etc/zabbix/zabbix.memory2.sh
#!/bin/sh

TEXT=$(cat /proc/meminfo |grep "\(MemTotal:\|MemFree:\|Buffers:\|Cached:\|Slab:\|PageTables:\|SwapCached:\|SwapTotal:\|SwapFree:\)" | awk '{print $2}'|tr '\n' ',')

IFS=','
set -- $TEXT

MemTotal=$1
MemFree=$2
Buffers=$3
Cached=$4
Slab=$8
PageTables=$9
SwapCached=$5
SwapTotal=$6
SwapFree=$7

apps=$(expr \( $MemTotal - $MemFree - $Buffers - $Cached - $Slab - $PageTables - $SwapCached \) \* 1024)
page_tables=$( expr $PageTables \* 1024)
swap_cache=$( expr $SwapCached \* 1024)
slab_cache=$( expr $Slab \* 1024)
cache=$( expr $Cached \* 1024)
buffers=$( expr $Buffers \* 1024)
unused=$( expr $MemFree \* 1024)
swap=$( expr \( $SwapTotal - $SwapFree \) \* 1024)

echo apps. $apps
echo page_tables. $page_tables
echo swap_cache. $swap_cache
echo slab_cache. $slab_cache
echo cached. $cache
echo buffers. $buffers
echo unused. $unused
echo swapd. $swap

exit

改良版の処理時間をtimeで計ってみると2倍に高速化できていました。

# time /etc/zabbix/zabbix.memory.sh
~
real    0m0.024s
user    0m0.001s
sys     0m0.004s

# time /etc/zabbix/zabbix.memory2.sh
~
real    0m0.011s
user    0m0.001s
sys     0m0.003s
zabbix-agentにUserParameterを追加する

ここまで来たらあとは簡単。/etc/zabbix/zabbix_agentd.confにUserParameterを追加するだけです。

# vi /etc/zabbix/zabbix_agentd.conf
+ UserParameter=vm.memory.size.m[*],/etc/zabbix/zabbix.memory.sh|grep "$1"| awk '{print $$2}'

# service zabbix-agent restart
# service zabbix-agent restart
Shutting down Zabbix agent:                                [  OK  ]
Starting Zabbix agent:                                     [  OK  ]

Zabbixサーバからzabbix_getコマンドで値を取得可能か確認します。

# zabbix_get -s 192.0.2.86 -k vm.memory.size.m[apps]
515538944
Zabbixにアイテムを登録する

UserParameterに追加したキー+[]の中に関ししたい項目を指定してアイテムを作成します。
zabbix_munin-like-memory_item

必要な分のアイテムを作成し、Zabbix上で各々のデータ取得ができることを確認したら、最後にグラフを作成します。グラフの色はMuninと同じものにしてみました。
zabbix_munin-like-graph-setting

メモリのグラフができた!

これで欲しい情報が入ったメモリのグラフを作成できました。
zabbix_munin-like-memorygraph

やっぱりZabbixのカスタマイズ性は抜群だと思います。Muninの自作プラグイン作成だったらこんなに簡単にはいきません。

スポンサーリンク

コメント

  1. jojojp より:

    /proc/meminfo の計算でとても助かりましたありがとうございます

    apps=MemTotal-MemFree-Buffers-Cached-Slab-PageTables-SwapCached
    この計算式はすばらしい