<経緯>
現在、運用テスト中のシステムにおいて障害監視をzabbixで行っていますが、監視対象のシステムが今ひとつ安定性に欠けており、油断すると大量のログを吐き出します。
※MiddleWareのログ(テキスト)やWindowsのイベントログなど。
大量のログを検知するとzabbixが発生した件数分のメールを発報して、メールシステムに負荷を掛けてしまうのでその回避方法を検討して以下の方法になりました。
ある時、イベントログに1000行以上、エラーが吐かれてそれをzabbixが全件拾い上げて1000通以上のメールがメールサーバに蓄積されてしまいました。メールサーバで同一送信元からのメールの流量を制限しているため、なかなかメールが捌けずに別のエラー発報が待ち行列の最後に回りエラー通報に気づかない事象が発生しました。
<方法>
zabbixはトリガーで監視対象を検知すると、MySQLのテーブル(zabbix.alerts)に発報内容を書き出します。
それを順次定義された内容(この場合はメール送信)に従って実行し、送信後ステータスを送信済み(status=”1”)に更新します。
今回は、メールの件名毎の未送信(status="0")件数をカウントし、閾値を超えている場合は、強制的に送信後ステータスを送信済み(status=”1”)に更新するようにしました。
以下のshellを1分おきにcrontabで起動し、閾値(check_count)を超えていれば、テーブルをupdateします。
1分おきの監視なので、先頭の数十件はalertsテーブルに格納とともに、メール送信され残りは送信されないようにいい感じに動いています。
crontabの実行間隔(現在1分おき)と、監視する件数(現在30件)をサーバの能力などに合わせて調整して頂ければ、よいかと思います。
※また、件数のチェック時ですが、zabbixのトリガーに複数のメールアドレスが登録されている場合、メールアドレス分のレコードがalertsテーブルに書き込まれるので、代表のメールアドレスで絞り込んでいます。
※更新のSQLからは、メールアドレスは外してください。
※「文字コードをLatin->UTF8に変更」はインストール時に文字コードがUTF8でインストールされていなかったみたいで、文字化けするので入れています。
※SQL(MySQLの接続)が3セクションありますが、2番目のセクションだけで機能は満たせます。
また、3セクションを一つにまとめても問題ありません。
#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# Purpose : Zabbixのアラートをある程度抑制する。
# -----------------------------------------------------------------------------
set -eu
logdir=/logs/zabbix
shname=`basename $0 ".sh"`
check_count=30 # 抑止する件数(閾値)
logflnm=$logdir/$shname.log
###------------
### PROC
###------------
### touch $logflnm
{
mysql -s -uzabbix -pzabbix <<EOF
-- 文字コードをLatin->UTF8に変更
SET NAMES utf8;
-- zabbixに接続
USE zabbix;
-- 未送信の同一件数をチェック(${check_count}件以上)
select sysdate(),a.subject,count(*) as kensu from alerts a
where a.status="0"
and a.sendto = "hogehoge@fugafuga.com"
group by a.subject
having kensu > ${check_count};
exit
EOF
mysql -s -uzabbix -pzabbix <<EOF
-- 文字コードをLatin->UTF8に変更
SET NAMES utf8;
-- zabbixに接続
USE zabbix;
-- 未送信で${check_count}件以上のメッセージのステータスを送信済みに更新。
update alerts x
set x.status="1"
where x.subject in(
select b.title from (
select a.subject as title,count(*) as kensu from alerts a where a.status="0" group by title having kensu > ${check_count} ) b)
and x.status="0";
exit
EOF
mysql -s -uzabbix -pzabbix <<EOF
-- 文字コードをLatin->UTF8に変更
SET NAMES utf8;
-- zabbixに接続
USE zabbix;
-- 未送信の同一件数をチェック(${check_count}件以上)
select sysdate(),a.subject,count(*) as kensu from alerts a
where a.status="0"
and a.sendto = "hogehoge@fugafuga.com"
group by a.subject
having kensu > ${check_count};
exit
EOF
} >> $logflnm 2>&1
exit $?