BLOG
2018 年 12 月 03 日
Zabbix 3.2以降の新機能解説(Zabbix 4.0を見据えて) その18 - トリガーベースのメインテナンス(その1)
こんにちは、MIRACLE ZBX サポートを担当している花島タケシです。今回は、ようやく実装されたトリガーベースのメインテナンスについて解説します。
トリガーベースのメインテナンス
4.0.0beta1 にてようやく実装されました
Zabbix 4.0 に追加された機能のうち、代表的なものにトリガーベースのメインテナンスがあります。
と言っても、正確にはトリガーベースというよりもタグベースとなります。
タグ付きイベントはトリガーからしか生成されないため、実質トリガーベースと言っても問題ないとは思います。
本当にトリガーベースのメインテナンスと呼べるのか ?
このトリガーベースのメインテナンスは長らく ZBXNEXT-413 にて提案されてきたものです。
投稿は 1.8.2 時のものとなり、8 年以上前となります。
今回漸く実装されたのですが、実装調査を行った上での感想としては、正直がっかり機能です。( 個人的な感想です。)
想定としては、あるトリガーの判定が真となり障害が発生した場合、そのホストをメインテナンス状態にするようなものや、特定のアイテムの監視を停止するようなものでした。しかしながら、動作確認を行ったところそのようになっておらず、設定したメインテナンスの時刻になれば、Timer プロセスにより対象となるホストはメインテナンス状態になります。
では、「何が起こるか ?」というと、「アクションが抑止される」に過ぎません。
トリガーベースメインテナンスの概要
このトリガーベースのメインテナンスは、イベント、障害を生成した後に抑止情報を生成する前半処理と生成された抑止情報を管理する後半の二つに分けられます。
前者は、以前と変わらずに、DB Syncer プロセスにより行われます。
つまり、ヒストリキャッシュから DB へデータを書き込むときにトリガー判定が行われ、イベントが生成されます。この一連の処理においてトリガーのタグにマッチしたものについては抑止情報が生成されます。
後者は、Timer プロセスにより行われます。4.0 より Timer プロセスが Timer 系関数を含むトリガー式の評価が行われなくなったことは、前回までに記述しております。つまり、Timer プロセスはメインテナンスの処理だけを行うように変更されています。
前者と後者のデータの受け渡しは DB 経由となります。このために event_suppress テーブルが追加されました。
この一連の処理について二回に分けて解説を行う予定です。今回は DB Syncer プロセスが、events, problem, event_suppress テーブルへデータを挿入するまでを解説します。
この event_suppress テーブルへ書き込まれるデータが抑止情報となります。
DB Syncer の処理
ヒストリキャッシュから DB へのデータ書き込み処理が 3.0.x より変更されたことは以前の記事で紹介しました。ですが、DB Syncer がヒストリデータを DB へ書き込むときに、トリガー評価を行い、イベントを生成するといった流れに変わりはありません。
DB Syncer のメインループから、sync_history_cache() がコールされ、書き込み処理が開始されます。( 以下、ソースコード解説は 4.0.0beta1 を用いて行います。)
ここから、src/libs/zbxdbcache/dbcache.c : sync_server_history() → src/zabbix_server/events.c : zbx_process_events() → src/zabbix_server/events.c : flush_events() とコールして処理が進められます。
1891 static int flush_events(void)
1892 {
1893 int ret;
1894 zbx_event_recovery_t *recovery;
1895 zbx_vector_uint64_pair_t closed_events;
1896 zbx_hashset_iter_t iter;
1897
1898 ret = save_events();
1899 save_problems();
1900 save_event_recovery();
1901 update_event_suppress_data();
1902
1903 zbx_vector_uint64_pair_create(&closed_events);
以前紹介した記事から、update_event_suppress_data() が増えています。
diff を取ってみると、その前 3 つの関数に変更はありません。
1840 /******************************************************************************
1841 * *
1842 * Function: save_event_suppress_data *
1843 * *
1844 * Purpose: retrieve running maintenances for each event and saves it in *
1845 * event_suppress table *
1846 * *
1847 ******************************************************************************/
1848 static void update_event_suppress_data(void)
1849 {
...
1858 /* prepare trigger problem event vector */
1859 for (i = 0; i < events_num; i++)
1860 {
1861 if (0 == (events[i].flags & ZBX_FLAGS_DB_EVENT_CREATE))
1862 continue;
1863
1864 if (EVENT_SOURCE_TRIGGERS != events[i].source)
1865 continue;
1866
1867 if (TRIGGER_VALUE_PROBLEM == events[i].value)
1868 zbx_vector_ptr_append(&event_refs, &events[i]);
1869 }
1870
1871 if (0 == event_refs.values_num)
1872 goto out;
1873
1874 if (SUCCEED != zbx_dc_get_running_maintenanceids(&maintenanceids))
1875 goto out;
1876
1877 if (0 != event_refs.values_num)
1878 add_event_suppress_data(&event_refs, &maintenanceids);
1879 out:
1880 zbx_vector_ptr_destroy(&event_refs);
1881 zbx_vector_uint64_destroy(&maintenanceids);
1882 }
l.1859 で使用される events_num はグローバル変数です。処理すべきイベントの数となります。ll.1858-1869 のブロックは、ほぼイベントソースがトリガーで障害となっているイベントを event_refs 配列に記憶している処理と言えます。対象となるイベントは、( まだ処理のされていない ) 全てのイベントとなります 。(ZBX_FLAGS_DB_EVENT_CREATE フラグは、作成された直後のイベントに付与されます。 したがって、生成された直後の未処理のイベントを抽出しています。)
l.1874 の zbx_dc_get_running_maintenanceids() は、現在時刻がメインテナンスの期間にマッチするメインテナンスを抽出しています。
src/libs/zbxdbcache/dbconfig_maintenance.c
1455 int zbx_dc_get_running_maintenanceids(zbx_vector_uint64_t *maintenanceids)
1456 {
1457 zbx_dc_maintenance_t *maintenance;
1458 zbx_hashset_iter_t iter;
1459
1460 RDLOCK_CACHE;
1461
1462 zbx_hashset_iter_reset(&config->maintenances, &iter);
1463 while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter)))
1464 {
1465 if (ZBX_MAINTENANCE_RUNNING == maintenance->state)
1466 zbx_vector_uint64_append(maintenanceids, maintenance->maintenanceid);
1467 }
1468
1469 UNLOCK_CACHE;
1470
1471 return (0 != maintenanceids->values_num ? SUCCEED : FAIL);
1472 }
l.1465 の各メインテナンスのスタートが ZBX_MAITENANCE_RUNNING であるかの判定を 行っていますが、state メンバーは同じソースの zbx_dc_update_maintenances() において、現在時刻がメインテナンスの期間内にあるときのみ ZBX_MAINTENANCE_RUNNING に変更しています。つまり、zbx_dc_get_running_maintenanceids() にて抽出しているメインテナンスは、上記の「現在時刻がメインテナンスの期間にマッチする」ものということになります。コードを読み進んでいるときに RUNNING という文字に惑わされましたが、そういう意味であることがわかります。( 開始日時、終了日時と異なるので注意してください。)
最後に、l.1878 の add_event_suppress_data() にて event_refs と maintenanceids の突き合わせをしています。
add_event_suppress_data() はちょっと長いため、適当に端折って見ていくこととします。
1759 static void add_event_suppress_data(zbx_vector_ptr_t *event_refs, zbx_vector_uint64_t *maintenanceids)
1760 {
...
1789 if (0 != event_queries.values_num)
1790 {
...
event_queries は、event_refs から生成した処理のための構造体配列 ( 実際にはちょっと違うけど ) です。
いわば、イベント情報のサブセットとなります。当然 eventid は一意となるため、event_queries の各要素は eventid ごとのデータとなります。
生成される event_queries は下図のようになります。
1794 if (SUCCEED == zbx_dc_get_event_maintenances(&event_queries, maintenanceids) &&
1795 SUCCEED == zbx_db_lock_maintenanceids(maintenanceids))
1796 {
1797 zbx_db_insert_prepare(&db_insert, "event_suppress", "event_suppressid", "eventid",
1798 "maintenanceid", "suppress_until", NULL);
1799
1800 for (j = 0; j < event_queries.values_num; j++)
1801 {
1802 query = (zbx_event_suppress_query_t *)event_queries.values[j];
1803
1804 for (i = 0; i < query->maintenances.values_num; i++)
1805 {
1806 /* when locking maintenances not-locked (deleted) maintenance ids */
1807 /* are removed from the maintenanceids vector */
1808 if (FAIL == zbx_vector_uint64_bsearch(maintenanceids,
1809 query->maintenances.values[i].first,
1810 ZBX_DEFAULT_UINT64_COMPARE_FUNC))
1811 {
1812 continue;
1813 }
1814
1815 zbx_db_insert_add_values(&db_insert, __UINT64_C(0), query->eventid,
1816 query->maintenances.values[i].first,
1817 (int)query->maintenances.values[i].second);
1818
1819 ((DB_EVENT *)event_refs->values[j])->suppressed = ZBX_PROBLEM_SUPPRESSED_TRUE;
1820 }
1821 }
1822
1823 zbx_db_insert_autoincrement(&db_insert, "event_suppressid");
1824 zbx_db_insert_execute(&db_insert);
1825 zbx_db_insert_clean(&db_insert);
1826 }
ll.1794-1795 では、zbx_dc_get_event_maintenances() にて、event_queries の各々のデータにおいて、 トリガー式からホストを抽出し、それと maintenaceids からマッチングを行い ( 当然メインテナンスの設定で対象のホストとホストグループを設定しています。)、さらにタグにもマッチしたメインテナンス ( 複数 ) をクエリーへと紐付けを行っています。( 上図で maintenances メンバーについて説明を加えてありますが、この関数がコールされるまでは空となります。)
つまり、抑止対象とするホストグループやホストは複数指定することはできますが、起点となるトリガー ( 式 ) に使用されているホストがこれに含まれていないと、タグのマッチングがあったとしてもメインテナンスの対象とならないということです。( これは、メインテナンスの対象に一つのホストとタグを設定し、そのホストともう一つのホストのアイテムを用いて、同じタグのトリガーを作成することで確認できます。)
そして、ホストとタグの二つにマッチしたメインテナンスは、先ほど空であった maintenances ペア配列に付与されます。
また、maintenanceids に入っているメインテナンス情報はメインテナンス期間であることが上で保証されているため、ここに付与されたということは抑止対象状態になるべきということです。
ll.1800-1821 のブロックでは、上の「抑止状態になるべき」ということから event_suppress テーブルへの挿入のための処理を行います。そして、l.1819 にてそのようにステータスの変更をしています。
event_refs->values はイベントデータのポインタであるため、直接イベントのメンバーを変更していることになります。
最終的に Escalator プロセスはこのステータスを用いてアクションの実行を抑止しています。
今回の締め
ここまででトリガーベースのメインテナンスの前半部分を解説しました。というより、現在の実装が正しいとすれば、上記がほぼ全てと言えます。
再度記述しますが、メインテナンスの設定に複数のホストグループやホストを設定したとしても、イベントの由来となったトリガーに使用されているアイテムのホスト以外は抑止対象とならないことは重要です。
また、この機能はメインテナンス期間のアクションを従来のものより柔軟に制御するためのものと言えます。
また、( 内部的な ) イベントデータの抑止情報はアラート実行において一応は参照されますが event_suppress テーブルのデータはほぼ利用されません。
次回は、Timer プロセスによる処理を紹介します。
関連記事
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 1
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 2
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 3
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 4
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 5
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 6
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 7
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 8
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 9
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 10
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 11
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 12
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 13
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 14
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 15
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 16
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 17
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 18
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 19
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 20
Zabbix 3.2 以降の新機能解説(Zabbix 4.0 を見据えて) その 21
注意事項
- 本ドキュメントの内容は、予告なしに変更される場合があります。
- 本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
- 本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。