2018 年 03 月 20 日
Runtime Control 機能の解説
今回は、再起動を行うことなく設定を変更できる Runtime Control 機能について解説します。
はじめに
Zabbix サービスのデーモンは起動時に設定ファイルを読み込み、その内容に則て動作します。
動作を変更するには、該当する設定を変更しサービスを再起動することが必要ですが、いくつかの動作については Zabbix サービスを起動したまま、再起動を行うことなく変更することができます。
この機能を Runtime Control と呼びます。
この機能にはいくつかのオプションがあり、それぞれ以下の表にあることを行うことができます。
オプション | 機能 | 対応サービス |
---|---|---|
config_cache_reload | Configuration Cache のリロード | Zabbix サーバ Zabbix プロキシ |
housekeeper_execute | Housekeeping の手動実行 | Zabbix サーバ Zabbix プロキシ |
log_slow_queries | LogSlowQueries の変更 | Zabbix サーバ |
log_level_increase log_level_decrease |
ログレベルの変更 | Zabbix サーバ Zabbix エージェント Zabbix プロキシ |
※log_slow_queries オプションは、当社が独自に追加した MIRACLE ZBX のみにある機能です。
本ドキュメントでは、オプションの中から、log_slow_queries、log_level_increase、log_level_decrease オプションについて解説を行います。
調査環境
MIRACLE ZBX 3.0.13-1
使用方法
Runtime Control はそのオプションを Zabbix サービスを起動するコマンド (zabbix_server,zabbix_agent,zabbix_proxy) に "-R" を付与し、その引数として渡すことで実行します。
# zabbix_server -R < オプション >
各オプションについての説明は、--help を指定した実行結果で確認できます。
# zabbix_server --help
< オプション > log_slow_queries
指定した時間 ( ミリ秒 ) 以上を要した DB クエリをログに出力するようにします。
該当する設定ファイルのパラメータは LogSlowQueries(zabbix_server.conf) です。
実行例
# zabbix_server -R log_slow_queries=3000 zabbix_server [3689]: command sent successfully
< オプション > log_level_inclrease / decrease
ログレベルを変更します。特定のプロセス、又は全てのプロセスのログレベルを変更することができます。
該当する設定ファイルのパラメータは DebugLevel(zabbix_server.conf,zabbix_agentd.conf) です。
実行例
全ての Zabbix サーバのプロセスのログレベルを上げる場合
# zabbix_server -R log_level_increase zabbix_server [2920]: command sent successfully
特定のプロセスのログレベルを上げる場合は、オプションに続けてターゲットとして対象の PID 又は、プロセスのタイプ、及びプロセスの見出し番号を指定します。
書式
# zabbix-server -R < オプション > < ターゲット >
< オプション >
log_level_increase= ターゲット
log_level_decrease= ターゲット
< ターゲット >
PID: 指定したプロセスのデバッグレベルを変更する。
process-type: 指定したタイプの全てのプロセスのデバッグレベルを変更する。
process-tyep,N: 指定したタイプの見出し番号 N のプロセスのデバッグレベルを変更する。
※ターゲットの PID、見出し番号 (N)、process_type に指定できる値は ps コマンドを使用して確認することができます。
# ps -ef
UID PID PPID C STIME TTY TIME CMD
...
zabbix 9620 9613 0 19:22 ? 00:00:00 /usr/sbin/zabbix_server: poller #1 [got 0 values in 0.000004 sec, idle 5 sec]
...
例えば、上記のプロセスを指定する場合、それぞれの値は下記となります。
PID: 9620
process-type:poller
N:1
実行例
Poller プロセス N:4 の DebugLevel を上げる。
# zabbix_server -R log_level_increase=poller,4 zabbix_server [3479]: command sent successfully
PID:2920 のプロセスの Debuglevel を上げる。
# zabbix_server -R log_level_decrease=2920 zabbix_server [3492]: command sent successfully
実装調査
この機能は、動作中のプロセスに対してシグナルを送信し、そのプロセスにオプションに該当する処理を実行させて実現しています。
シグナル処理の実装では、一般的に 1 つのシグナルに対して、1 つのシグナルハンドラしか割り当てません。
この処理は、シグナルと共に引数をシグナルハンドラに渡し、引数で分岐させた処理を実行させることにより、1 つのシグナルで複数種類の処理を行う実装となっています。
具体的には、ユーザ定義シグナルである SIGUSR1 と sigqueue() を利用して、オプションに渡したデータをプロセスに送信しています。
Zabbix の各種サービスを起動するコマンドに "-R" を付与してその引数に Runtime Control のオプションを渡して実行すると、既に起動している Zabbix サービスの親プロセスに対して、シグナルと引数のデータを送ります。
そのシグナルとデータを受け取った親プロセスが動作の変更を行う子プロセス群を選出し、それらに対してシグナルとデータを送ります。受け取った子プロセスは、該当する動作を変更する処理を実行します。
上記の処理がどのように実装されているか、Zabbix サーバのソースコードで確認します。
(Zabbix エージェント、Zabbix プロキシについては同様の実装であるため、説明は割愛します。)
zabbix-server のメイン関数において parse_rtc_options() によりコマンド実行時にオプションの引数として渡された文字列のパーズを行います。
zbx_sigusr_send() によりパーズしたデータとシグナルをデーモンの親プロセスに送ります。
src/zabbix_server/server.c
int main(int argc, char **argv) { ... while ((char)EOF != (ch = (char)zbx_getopt_long(argc, argv, shortopts, longopts, NULL))) { switch (ch) { ... case 'R': opt_r++; if (SUCCEED != parse_rtc_options(zbx_optarg, program_type, &t.data)) exit(EXIT_FAILURE); } } ... if (ZBX_TASK_RUNTIME_CONTROL == t.task) exit(SUCCEED == zbx_sigusr_send(t.data) ? EXIT_SUCCESS : EXIT_FAILURE); ... }
zbx_sigusr_send() では、PidFile(zabbix_server.conf) に指定した PID ファイルから、プロセス ID を取得し、そのプロセスに対して、sigqueue() によりシグナル SIGUSR1 とオプションのデータを送ります。
src/libs/zbxnix/daemon.c
int zbx_sigusr_send(int flags) { ... if (SUCCEED == read_pid_file(CONFIG_PID_FILE, &pid, error, sizeof(error))) { ... if (-1 != sigqueue(pid, SIGUSR1, s)) { zbx_error("command sent successfully"); ret = SUCCEED; } ... return ret; }
親プロセスはシグナルと共にオプションのデータを受け取ると、オプションに該当する子プロセスの PID をリストから取り出し、今度はその子プロセスの PID に対して SIGUSR1 とオプションのデータを送ります。
シグナルとデータを受け取った子プロセスは同様に user1_signal_handler() をコールします。更に、common_sigusr_handler() をコールしてオプションに該当する処理を行います。
src/libs/zbxnix/daemon.c
static void user1_signal_handler(int sig, siginfo_t *siginfo, void *context) { ... if (!SIG_PARENT_PROCESS) { common_sigusr_handler(flags); return; } ... switch (ZBX_RTC_GET_MSG(flags)) { ... case ZBX_RTC_LOG_SLOW_QUERIES: zbx_signal_process_by_pid(ZBX_RTC_GET_SCOPE(flags), flags); break; case ZBX_RTC_LOG_LEVEL_INCREASE: case ZBX_RTC_LOG_LEVEL_DECREASE: if ((ZBX_RTC_LOG_SCOPE_FLAG | ZBX_RTC_LOG_SCOPE_PID) == ZBX_RTC_GET_SCOPE(flags)) zbx_signal_process_by_pid(ZBX_RTC_GET_DATA(flags), flags); else zbx_signal_process_by_type(ZBX_RTC_GET_SCOPE(flags), ZBX_RTC_GET_DATA(flags), flags); break; } ... }
common_sigusr_handler() では、オプションに該当する関数をコールします。
src/libs/zbxnix/daemon.c
static void common_sigusr_handler(int flags) { ... switch (ZBX_RTC_GET_MSG(flags)) { ... case ZBX_RTC_LOG_LEVEL_INCREASE: if (SUCCEED != zabbix_increase_log_level()) ... case ZBX_RTC_LOG_LEVEL_DECREASE: if (SUCCEED != zabbix_decrease_log_level()) ... case ZBX_RTC_LOG_SLOW_QUERIES: slow_queries = ZBX_RTC_GET_DATA(flags); if (SUCCEED != zabbix_set_log_slow_queries(slow_queries)) ... } ... } }
各関数では、対応する設定パラメータの値が保持されているグローバル変数の値を指定した内容に変更します。これにより該当するプロセスの動作が変更されます。
int zabbix_increase_log_level(void) { if (LOG_LEVEL_TRACE == log_level) return FAIL; log_level = log_level + 1 return SUCCEED; }
参考情報
注意事項
- 本ドキュメントの内容は、予告なしに変更される場合があります。
- 本ドキュメントは、限られた評価環境における検証結果をもとに作成しており、全ての環境での動作を保証するものではありません。
- 本ドキュメントの内容に基づき、導入、設定、運用を行なったことにより損害が生じた場合でも、当社はその損害についての責任を負いません。あくまでお客さまのご判断にてご使用ください。