【SNMP】標準 MIB で CPU / メモリ / Disk の使用率を計算するスクリプトを作る

こんにちは。
とあるネットワーク機器をモニタリングする必要があり、SNMP を用いたリソース情報の取得諸々について調べてみたので備忘録を残しておきます。

※ というのも普段 Linux デバイスに定義されている UCD-SNMP-MIB が定義されていなかったため、どうすればいいんだろう?と悩んだ結果です。 SNMPv2 前提です。

メモリ/ディスク

メモリ / ディスク の情報については、hrStorageDescr の OID で一覧と割り当てられた index 番号を取得できるようです。

[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrStorageDescr
HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory
HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Virtual memory
HOST-RESOURCES-MIB::hrStorageDescr.6 = STRING: Memory buffers
HOST-RESOURCES-MIB::hrStorageDescr.7 = STRING: Cached memory
HOST-RESOURCES-MIB::hrStorageDescr.8 = STRING: Shared memory
HOST-RESOURCES-MIB::hrStorageDescr.10 = STRING: Swap space
HOST-RESOURCES-MIB::hrStorageDescr.35 = STRING: /dev/shm
HOST-RESOURCES-MIB::hrStorageDescr.37 = STRING: /run
HOST-RESOURCES-MIB::hrStorageDescr.38 = STRING: /sys/fs/cgroup
HOST-RESOURCES-MIB::hrStorageDescr.55 = STRING: /
HOST-RESOURCES-MIB::hrStorageDescr.63 = STRING: /run/user/1000

※ 上記だと、index 1 が物理メモリ、index 55 がディスクの ルートパーティション となります。

index を参考に下記の OID を取得することで、Total / 使用量 / 使用率 が割り出せます。

HOST-RESOURCES-MIB::hrStorageAllocationUnits
HOST-RESOURCES-MIB::hrStorageSize
HOST-RESOURCES-MIB::hrStorageUsed

※ 計算式は下記の通りです。
Total = HOST-RESOURCES-MIB::hrStorageSize * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用量 = HOST-RESOURCES-MIB::hrStorageUsed * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用率 = 使用量 / Total * 100

諸々を bash と awk でスクリプトに纏めると下記の通りとなります。
※ シェルスクリプトだと小数点が扱えないので、演算部分は awk で賄います。
※ 第一引数に求める値(Total/使用量/使用率)、第二引数に領域の index を指定します。

#!/usr/bin/bash

# MEMO: 引数チェック
if [ $# != 2 ]; then
    echo "ERR:invalid argument"
    exit 1
fi

COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx

ALLOCATIONUNITS=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageAllocationUnits | grep "HOST-RESOURCES-MIB::hrStorageAllocationUnits.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGESIZE=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageSize | grep "HOST-RESOURCES-MIB::hrStorageSize.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGEUSED=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageUsed | grep "HOST-RESOURCES-MIB::hrStorageUsed.${2} = INTEGER:" | awk '{print $4}'`

USED_MEMORY=$(( HRSTORAGEUSED * ALLOCATIONUNITS ))
ALL_MEMORY=$(( HRSTORAGESIZE * ALLOCATIONUNITS ))

USED_RATIO=`awk "BEGIN { print $USED_MEMORY / $ALL_MEMORY * 100 }"`

case ${1} in
    # NOTE: Total
    "1")
        echo ${ALL_MEMORY}
        ;;
    # NOTE: Used
    "2")
        echo ${USED_MEMORY}
        ;;
    # NOTE: Ratio
    "3")
        echo ${USED_RATIO}
        ;;
    # NOTE: Ratio
    *)
        echo ${USED_RATIO}
        ;;
esac

CPU

CPU 使用率は hrProcessorLoad の OID で1コア辺りの 使用率を参照できます。

[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrProcessorLoad
HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 2

※ 上記だとノードに 8コアの CPU が詰まれていて、1コア辺り 2% の使用率となる。

こちらも bash と awk でスクリプトに纏めると下記の通りとなります。
※ 1 コア辺りの平均値を求めます。

#!/usr/bin/bash

COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx

TOTAL_CPU_LOAD=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | awk '{print $4}' | awk '{s += $1} END {print s}'`
CPU_NUM=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | wc -l`

echo $(( TOTAL_CPU_LOAD / CPU_NUM ))

終わりに

上 2つのスクリプトで対象の機器に対してポーリング → DB にデータ格納 でモニタリングできますね。

awk で特定の行の値を取得して計算してみる(Linux のモニタリングツールを作る)

Linux のモニタリングツールといえば、dstat、sarなんかが有名だと思いますが、環境によってはツールが入っていないこともしばしば。
というわけで、linux にプリインストールされているコマンドで必要最低限のモニタリングツールを用意してみます。

ログ調査とかテキストの整形とかでお世話になる awk ですが、実は計算が出来るんですよね。
例えば、 cat /proc/meminfo の出力結果から実メモリの使用率を計算してみようと思います。

/proc/meminfo

ちなみに meminfo の内容はこちら。
MemTotal、MemFree、MemAvailable の値を取得できれば、メモリ使用率を求めることができそうですね。
※ 今回はawkの挙動を確認したいので、あえて MemTotal と MemAvailable を取得してみます。

[root@verienv01 ~]# cat /proc/meminfo | head
MemTotal:         498672 kB
MemFree:           77104 kB
MemAvailable:     363416 kB
Buffers:               0 kB
Cached:           261200 kB
SwapCached:            4 kB
Active:           147176 kB
Inactive:         150668 kB
Active(anon):        492 kB
Inactive(anon):    43400 kB

awkでメモリ使用率を求める

awk で行を指定したい場合は「NR」を使えばよくて、1行目と3行目で且つ、スペースで区切った左から2列目の値を取得したいのでこうですね。

[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {print $2} NR==1 {print $2}'
498672
363332

取得した値をワンライナーで変数ava(MemAvailable)と変数total(MemTotal)に入れて、計算まで行う場合はこうです!
[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}'
27.1136

小数点以下は切り捨てます。
これでバッファキャッシュも考慮したメモリ使用率を出力できましたね。
[root@verienv01 ~]# cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}' | sed s/\.[0-9,]*$//g
27

モニタリングツール

というわけで、CPU使用率、メモリ使用率、ロードアベレージ、タイムスタンプを出力するシェルスクリプトを用意します。

#!/bin/bash

MEMORY=$(cat /proc/meminfo | awk 'NR==3 {ava=$2} NR==1 {total=$2} {per = ava / total}END{print 100 - per * 100}' | sed s/\.[0-9,]*$//g)
CPU=$(vmstat | awk 'NR==3 {print $13,$14}')
LA=$(uptime | awk '{print $8,$9,$10}')
TIME=$(vmstat -t | awk 'NR==3 {print $18,$19}')

echo "--cpu-- --mem--  --------la--------  --------time--------"
echo " " $CPU "    " $MEMORY "   " $LA " " $TIME

いろいろとツッコミ処があると思いますが、、まぁいいでしょう。
[root@verienv01 ~]# ./monitor.sh
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-05 23:56:43

whileでループすれば、モニタリングツールの出来上がり(小並感)
[root@verienv01 ~]# while true; do ./monitor.sh ; sleep 1; done
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:42
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:43
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:44
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:45
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:46
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:48
--cpu-- --mem--  --------la--------  --------time--------
  0 0      27     0.00, 0.01, 0.01   2020-12-06 00:02:49

終わりに

正直 dstat と sar と vmstat でいいですね。