こんにちは。技術部の髙岡です。
ZabbixのダッシュボードのProblemsがいつまで経っても表示されないことがあります。
そんな時にどうすればよいのかを検証してわかったことを書いてみたいと思います。
原因
PostgreSQLとかMariaDBのようなデータベースのeventsテーブルの件数が数百万件のようなレベルで異常に増えてしまい、Zabbixからデータベースに発行されるクエリーに時間を要していることが原因でした。
スロークエリーがログファイルに出力されるようにデータベースを設定すると、Zabbixのダッシュボードを開いた時に以下の例ようなeventsテーブルとevent_recoveryをJOINするSELECT文が、10秒前後とかそれ以上の時間で実行されていることがわかります。
SELECT DISTINCT e.eventid,e.clock,e.ns,e.objectid,e.acknowledged,er1.r_eventid FROM events e LEFT JOIN event_recovery er1 ON er1.eventid=e.eventid WHERE e.source='0' AND e.object='0' AND e.objectid='17333' AND e.eventid<='10781489' AND e.value='1' ORDER BY e.eventid DESC LIMIT 20;
eventsテーブルには、
①発生したトリガー(障害発生)の情報
②ディスカバリの情報
③自動登録の情報
④内部イベント
が記録されています。
よくあるのが、①のようなレコードが大量に書き込まれてしまったケースかと思います。
運用開始前のテストで大量にトリガーを起動させてしまったとか、運用開始後に大規模障害が発生してしまった状況で起こりうるケースです。
解決策
そもそも、トリガー(障害)が、何万件も発生していること自体が、監視システムとしては正常ではありませんので、発生する障害を減らすことが監視システムとしての本質的な解決策かと思います。
しかし、このような状況が発生してしまった後でどうすればいいのでしょうか?
上記のSELECT文の実行時間を短縮するための対処が必要です。
Zabbixのようにパッケージソフトウエアから発行されたSQL文を書き換えることができません。
したがって、以下の対策を候補として挙げることができます。
②eventsテーブルにインデックスを追加する。
③データベースのパラメータを変更する。
④ハードウェアのリソースを増やす。
①は、ZabbixのHousekeeperの設定でトリガーデータの保存期間を一時的に一日等に短縮することで実現可能です。
尚、eventsテーブルは5つのテーブルから参照制約で参照されているので、他のテーブルのレコードとの関連性が強いテーブルです。
なので、他への影響を考慮すると、eventsテーブルを直接deleteしたり、truncateしたりすることは個人的にはやりたくないと思っています。Zabbixのハウスキーピングを活用したデータ削除が無難かと。
しかし、運用開始済みで、監視履歴を保存する期間が例えば180日等で決まっており、Housekeeperを活用して一時的にでも保管期間を減らすことが運用上できない場合は、②、③、④のような対処が有効かと思います。
細かい話は抜きにして、検証した対処方法だけを先に書きます。
PostgreSQLだけに適用できる方法です。
尚、この方法を実践することによって発生したあらゆる不具合、不都合ついては一切の責任を負いません。
eventsテーブルへのインデックスを追加する。
zabbix=# create index event_4_add on events (source,object,objectid,eventid,value);
マシンのCPU個数を増やして、パラレルクエリーのプロセス数を増やす。
/db作成ディレクトリ/postgresql.conf の変更
(CPUの個数を20に増やした例)
max_worker_processes = 20 # (change requires restart) max_parallel_workers_per_gather = 15 # taken from max_parallel_workers max_parallel_workers = 15 # maximum number of max_worker_processes that
SELECT文の実行計画でパラレルクエリーが適用されるようにevnetsテーブルとevent_recoveryテーブルへのparallel workersの数を設定
zabbix=# alter table events set (parallel_workers=15) ; zabbix=# alter table event_recovery set (parallel_workers=15) ;
これで、SELECT文の実行時間を10秒前後やそれ以上の時間から3秒位に短縮できました。
ZabbixのダッシュボードのProblemsも、いつまで経っても表示されないのが、数秒で表示されるようになりました。
SELECT文の実行計画を見て、遅いフェーズを早くする手段を考えた末に選択した手段です。
実行計画の解析の詳細は、次回のブログで書きますが、Zabbixの話というよりも、もはやMariaDBとPostgreSQLのチューニングの話となってしまう予定です。