現在位置: ホーム / 製品・サービス / 統合システム監視 MIRACLE ZBX / MIRACLE ZBX - Zabbix テック・ラウンジ / ZabbixのSNMPトラップ受信をFluentdで負荷分散させる!

ZabbixのSNMPトラップ受信をFluentdで負荷分散させる!

Zabbix(あるいはMIRACLE ZBX)では、短時間に大量のSNMPトラップが送信される"バースト"が発生した場合に、トラップが欠損することがあります。本ドキュメントでは、ZabbixとFluentdを組み合わせることによってトラップ欠損を軽減するための方法を紹介します。

概要

Zabbix(あるいはMIRACLE ZBX)では、短時間に大量のSNMPトラップが送信される"バースト"が発生した場合にsnmptrapdがトラップを受信しきれない事があります。特にRHEL7.x系のOSではトラップを受信するsnmptrapdをバックグランドで複数起動する事ができなくなりましたので、複数のsnmptrapdインスタンスでSNMPトラップを受信しZabbixに送信する方法を考えます。

バーストによってSNMPトラップを欠損させる。

検証用にCentos7.2の仮想マシンを用意し、Zabbix3.0を構築してSNMPトラップのバーストを受けた時にトラップが欠損するか試してみます。SNMPトラップの受信にはSNMPTTではなくzabbix_trap_receiver.plを使用しました。

仮想マシン構成

 OS : CentOS7.2
 CPUコア : 1 core
 メモリ:2GB

擬似的にバーストを起こすために下記のスクリプトを作成し、受信側と同等スペックの仮想マシン3台から同時に実行します。

[root@localhost ~]# cat snmptrap_burst.sh
### 特定のホストにSNMPトラップ(linkDown)を指定回数送りつけるスクリプト
#!/bin/bash

declare -i i=5000
while [[ $i -gt 0 ]]
do
snmptrap -v 2c -c public <送信先アドレス> '' .1.3.6.1.6.3.1.1.5.3
i=$((i-1))
done

 

ZabbixのWEB UI上でSNMP Trapアイテムを作り、バースト後にDB内のhistory_logの中身をカウントしてトラップが欠損していないかを確認します。バースト発生前は下記のようにlog型のヒストリが無い状態でバーストを起こします。

MariaDB [zabbix]> select count(id) from history_log;
+-----------+
| count(id) |
+-----------+
| 0 |
+-----------+
1 row in set (0.01 sec)

 

バースト発生後、十分に時間を開けてから再びDBを確認します。

MariaDB [zabbix]> select count(id) from history_log;
+-----------+
| count(id) |
+-----------+
| 14985 |
+-----------+
1 row in set (0.01 sec)

 

疑似バーストで送信したトラップ総数は合計15000件(5000 x 3)なので、15件のトラップが欠損している事がわかります。(受信側ノード側のトラップ流量はおおよそ240件/秒ほどでした。)

zabbix_trap_receiver.plやZabbix自体の処理遅延によってトラップの欠損が起きている可能性を考慮して、snmptrapdのトラップ受信時の処理をログ出力のみに絞り出力されるログの行数を確認します。journald や rsyslogにはデフォルトで流量制限があるため、これを無効化してバーストを発生させます。

[root@localhost ~]# wc -l /var/log/snmpd/snmptrap.log
14996 /var/log/snmpd/snmptrap.log

件数は減少したものの、トラップの欠損は発生しました。

バーストの発生によってsnmptrapdがトラップを欠損する事が確認できました。これはsnmptrapdのバッファ(固定値)がオーバーフローすることが原因ですので、解決には複数のsnmptrapdを用意しバースト時のトラップを負荷分散することが必要となります。

snmptrapdの分散構成を考える。

ZabbixのSNMPトラップ監視では同一ホスト上のsnmptrapdが出力したログを監視するため、複数のsnmptrapdノードでトラップを受信する場合、各ノードで受信したトラップ情報をZabbixサーバーへ登録する仕組みが必要となります。今回は下記図のように各snmptrapdノードで受信したトラップをローカルにログ出力させ、そのログをFluentdによって整形しZabbix_senderを使ってサーバーへ情報を登録します。

 snmptrapd分散構成

図1. snmptrapdの分散構成

Fluentdはログの転送・集約ツールです。高度なバッファリング機能や豊富なプラグインによって様々な方法でログの取得・整形・送信が可能です。今回は下記の図の処理を行ってsnmpトラップを整形し、Zabbix senderを使ってZabbixへトラップの情報を送信します。

Zabbix+Fluentd構成

図2. Fluentdの処理概要 (※図をクリックすると拡大します)

受信したSNMPトラップをsnmptrapd.logに出力するようにsnmptrapdを設定し、td-agent.confに以下の設定を行います。

# ログを取得する。snmptrapdはsyslogフォーマットで出力するため、フォーマットはsyslogでよい。
<source>
@type tail
path /var/log/snmp/snmptrapd.log
pos_file /var/log/td-agent/snmptrapd.log.pos
tag snmp.trap
format syslog
</source>

# 余計なトラップをフィルターする。
<filter snmp.trap>
@type grep
regexp1 message IF-MIB::(linkUp|linkDown)
</filter>

# ログの一部からOID(MIB)を識別できる箇所を切り出し、タグに付与する。
<match snmp.trap>
@type rewrite_tag_filter
rewriterule1 message IF-MIB::linkUp linkUp.${tag}
rewriterule2 message IF-MIB::linkDown linkDown.${tag}
</match>

# 一塊になっていたSNMPトラップの情報を分割してレコードとして記録する。
<filter *.snmp.trap>
@type parser
format /^(?<date>.{19}) (?<host>[^ ]+).+\[(?<from_ip>[^ ]+)\].+\].+\].+\#012(?<timeticks>.+)#011(?<mib>.+)?$/
key_name message
</filter>

# アイテムのキー名としてタグをレコードに付与する。
<filter *.snmp.trap>
@type record_transformer
<record>
item_key ${tag}
</record>
</filter>

# 任意のメッセージをレコードに付与する。
<filter linkUp.snmp.trap>
@type record_transformer
<record>
  u_msg "test trap received : linkUp"
</record>
</filter>

<filter linkDown.snmp.trap>
@type record_transformer
<record>
u_msg "test trap received : linkDown"
</record>
</filter>

# Zabbixへトラップを送信するスクリプトを実行する。
<match *.snmp.trap>
@type exec
command bash /etc/td-agent/script/fluent2zbx.sh
buffer_path /var/log/td-agent/exe_buff-l01
format json
time_slice_format %Y-%M\m-%d-%H-%M-%S
time_slice_wait 1s
</match>

 

FluentdからZabbix senderを実行するためのラッパーシェルを作成します。

#!/bin/bash
IFS=$'\n';

RESULT=`bash /etc/td-agent/script/get_zbx_hosts.sh`

while read LINE
do
FROM_IP=`echo $LINE | jq -r .from_ip`
TIMETICKS=`echo $LINE | jq -r .timeticks`
MIB=`echo $LINE | jq -r .mib`
ITEM_KEY=`echo $LINE | jq -r .item_key`
U_MSG=`echo $LINE | jq -r .u_msg`

GET_HOST_NAME=`cat <<- EOS
  map(select(.["ip"] == "$FROM_IP"))
   EOS`
Z_HOST=`echo $RESULT | jq "${GET_HOST_NAME}" | jq .[].host`

ZBX_SENDER="zabbix_sender -z localhost -s $Z_HOST -k $ITEM_KEY -o \"$U_MSG [$TIMETICKS $MIB]\""
eval ${ZBX_SENDER}
done <$1

 

get_list_host-ip.shはZabbix APIを使用してsnmpトラップ内のIPアドレスからZabbixに登録されているホスト名を逆引きします。逆引き用のスクリプトは以下の通りです。

#!/bin/bash

URL='http://localhost/zabbix/api_jsonrpc.php'
ZABBIX_USER='zabbix'
ZABBIX_PASSWORD='zabbix'

function get_token() {
PARAMS=`cat <<- EOS
 {
  "jsonrpc": "2.0",
  "method": "user.login",
  "params": {
    "user": "${ZABBIX_USER}",
    "password": "${ZABBIX_PASSWORD}"
  },
  "id": 1
 }
 EOS`

curl -s -H 'Content-Type:application/json-rpc' \
 ${URL} \
 -d "${PARAMS}" | jq -r '.result'
}

function get_hosts() {
PARAMS=`cat <<- EOS
  {
   "jsonrpc": "2.0",
  "method": "host.get",
  "params": {
    "output": "extend",
    "selectInterfaces": "extend",
    "monitored_hosts":"True"
  },
  "id": 1,
   "auth": "${TOKEN}"
 }
 EOS`

curl -s -H 'Content-Type:application/json-rpc' \
 ${URL} \
 -d "${PARAMS}" | jq -r '.result | map({host: .host, ip: .interfaces[].ip})'
}

TOKEN=$(get_token)
echo $(get_hosts)

 

上記の設定ファイルを作成・配置し、td-agentを再起動したら続いてZabbix側の設定を行います。
ZabbixのWebインタフェースからSNMPトラップの送信元IPを設定したホストを作成します。

Webインターフェイス Host

 

続いて、作成したホストにfluentdから情報を受信する為のZabbixトラッパーアイテムを作成します。Fluentdで設定したタグをアイテムキーに設定し、データ型はログを指定します。

Webインターフェイス Item

 

ホストマシンからトラップを送信して、トラップが受信できるか確認します。

Webインターフェイス 最新データ

 

Zabbix + Fluentdの構成に、バーストを発生させる。

再び、バーストを発生させFluentdを使用した構成でログの欠損が発生するか確認します。

 

スクリプト実行後のログファイル 

[root@localhost ~]# wc -l /var/log/snmp/snmptrapd.log
0 /var/log/snmp/snmptrapd.log

 

スクリプト実行前のデータベース

MariaDB [zabbix]> select id from history_log;
Empty set (0.00 sec)

 

スクリプト実行後のログファイル 

wc -l /var/log/snmp/snmptrapd.log
15000 /var/log/snmp/snmptrapd.log

 

スクリプト実行後のデータベース 

MariaDB [zabbix]> select id from history_log;
15000 rows in set (0.00 sec)

 

snmptrapdを分散させた為、snmpトラップの欠損が発生していないことが確認できました。

 

まとめ

snmptrapdは高機能である反面、単体ではバースト発生時の高負荷状態下ではトラップの欠損といった問題が発生しますが、Zabbixの標準的なsnmpトラップ監視ではsnmptrapdとzabbix serverが1対1で紐づく構成であるため、柔軟な分散が難しいです。今回紹介した構成であれば、snmptrapdとzabbix serverを切り離して分散構成を組むことが出来るためsnmpトラップ流量増加やバーストが予想される環境であっても柔軟に受信負荷を分散することが可能となります。

 

注意事項

本ドキュメントの内容は、予告なしに変更される場合があります。
本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。

 

MIRACLE ZBX 製品・サポートサービス 詳しくはこちら

MIRACLE ZBX Virtual Appliance V3.0 評価版のお申し込み

製品・サービスについてのお問い合わせ

お問い合わせフォームMIRACLE ZBX製品やサポートサービスについてのご相談やご質問は、「お問い合わせフォーム」よりお気軽にお問い合わせください。