
本ブログでは、Alerts & AI 機能にて発生したインシデントが回復条件を満たしているはずなのに、クローズ (回復判定) されないというお問い合わせで最も多い原因であるゼロヌル問題に焦点を当てて解説いたします。また、静的閾値の設定の意味や注意すべきケース、そして NrAiSignal を用いたデータの確認方法をご紹介いたします。なお、アラートコンディションは NRQL型で静的な閾値を対象としており、信号消失 (Loss of Signal) の回復判定は対象としておりません。
ゼロヌル問題について
ダッシュボードや Query Your Data で出力される NRQL の結果と NRQL 型アラートパイプライン上で処理された結果では多少の違いがあります。顕著な例として、SELECT の count() や uniqueCount() があります。
アラートパイプライン上の処理では、WHERE 句の評価後に対象データが存在する場合は SELECT 句が実行されるため、WHERE 句の条件に合致するデータがなかった場合は、SELECT は実行されません。
つまり、count() および uniqueCount() などの集計が、ゼロ値を返すことはありません。カウントが 0 の場合、SELECT 句は無視され、データは返されず、結果値は NULL となります。
(例: 返されたnull値)
上記のドキュメントにもあるように下記のような NRQL アラートを設定し、閾値として、1以上を設定した場合は、回復することはありません。
SELECT count(*) FROM SyntheticCheck WHERE monitorName = 'My Cool Monitor' AND result = 'FAILED'
WHERE 句の条件として、result = 'FAILED' としているため、FAILED 以外のデータは SELECT されません。”ない (NULL)” は “数値として ゼロ (0)” とは評価されないため、1未満の値は記録されることはないため、回復条件は満たされることはありません。
対処方法としては、合わせて、信号消失の閾値を “Close all current open incidents” で設定することです。
result = 'FAILED' なデータが存在しなくなった場合、アラートパイプライン上では 対象データなし (NULL) と評価されます。そのまま NULL と評価され続け、信号消失閾値で設定した時間を超過すると、信号消失状態となり、インシデントがクローズされます。違反がない (正常な) 状態では信号消失状態、違反状態は、閾値で評価されるという形式となります。
ただこの方法では、違反がない (正常な) 状態でも、データが届いていない状態でも信号消失状態となるため、障害対応時にはその点を認識しておく必要があります。
(ブログ投稿)
また、別の方法としては、SELECT 句で filter 関数を用いる方法が挙げられます。NRQL の WHERE 句で条件を儲けるのでなく、SELECT 句の filter 関数でフィルタリングした結果を count することで 数値としてのゼロ (0) が記録できます。
SELECT filter(count(*), where result = 'FAILED') FROM SyntheticCheck WHERE monitorName = 'My Cool Monitor'
NRQL アラートのデフォルトサンプルとしても filter 関数を用いた方法が採用されていますが、FACET などと組み合わせると、評価対象が複雑になりがちであるため、シンプルなケース以外では注意が必要です。
静的閾値の設定と集計ウィンドウについて
アラートの静的閾値では、下記の 2種類の設定を選択することができます。
- at least once in N (time)
- 最新の集計から一定時間 (N time) 以内に、一度でも条件を満たしていたらアラートと判定 (= ANY)
- for at least N (time)
- 一定時間 (N time) 前から最新の集計まで、条件を満たす状態が継続していたらアラートと判定 (= ALL)
上記を正確に理解するためには、Window duration (集計ウィンドウ期間) で規定される集計ウィンドウとの関係を理解する必要があります。
アラートの評価対象となるデータは数秒おき (またはそれよりも短い時間で) 受信し続けるため、データの集計評価のためにある程度の時間幅 (集計ウィンドウの期間) に分割され、利用されます。
具体例をあげて説明すると
集計ウィンドウ期間を 1分と設定した場合、対象のデータは 1分おきのデータとして、区切られます。区切られた集計ウィンドウのデータで、average (平均) や max (最大値)、latest (最新値)、count (個数) など SELECT の内容で集計評価されます。なお、この各集計ウィンドウの評価された値を SignalValue (シグナル値) といいます。
データが区切られる時間が 1分間隔の場合は、12:00:00 - 12:01:00、12:01:00 - 12:02:00、12:02:00 - 12:03:00、といった具合に 00秒を起点に区切られます (※ 集計ウィンドウ期間を 30秒 で設定した場合は、30秒起きに区切られます)。
アラートの評価はこの集計ウィンドウを最小の単位として扱い、集計ウィンドウが閉じられると閾値の設定期間に応じたアラート評価が行われます。(閉じられるタイミングはストリーミングメソッドによって異なります)

閾値期間を for at least 5分 と設定した場合は、過去5分 (集計ウィンドウ5個分) のシグナル値 すべて が閾値条件を満たした場合、アラート判定となります。閾値設定の "N分間" は、集計ウィンドウ換算で何個分かということを意識する必要があります。また、この仕組みのため、静的閾値で設定できる期間は、集計ウィンドウ期間の整数倍の期間に制限されます。
一方、閾値期間を at least once in 5分 と設定した場合は、過去5分 (集計ウィンドウ5個分) の いずれか のシグナル値が閾値条件を満たした場合にアラート判定となります。閾値の評価は、集計ウィンドウが閉じられるたびに行われるので、実質的には最新のシグナル値が閾値条件を満たせば、インシデントが発生することになります。

また「集計ウィンドウ期間を 1分にして、静的閾値を at least once in 5分」とした場合と「集計ウィンドウ期間を 5分にして、静的閾値を at least once in 5分」とした場合では、一見同じに見えますが、集計ウィンドウが閉じられたタイミングで閾値の評価が行われるので、前者は 1分間隔で検知できますが、後者は 5分おきの検知となります。後者はスライディングウィンドウ設定を行うことで、検知時間を短縮することができます。
静的閾値設定における NULL の影響について
”for at least N (time)” では、すべての集計ウィンドウの値が閾値条件を満たした場合、違反と判定されますが、途中でデータ受信が大きく遅延し、NULL 評価となった集計ウィンドウがあった場合、どのような動作をするでしょうか?
先と同様に集計ウィンドウ期間を 1分間、for at least 5分と設定した場合で、下記のようなデータだったとします。00分のデータは正常値でしたが、01分から障害値を記録し始め、その後、障害値が継続しています。しかし 03分のデータが抜けてしまい、NULL となっています。

この場合、障害値を記録し始めた 01分から、5分以上が継続した 05分の集計ウィンドウが閉じたタイミングでで違反となるように思われるかもしれませんが、実際は (5個) すべての集計ウィンドウが条件を満たす必要があるため、08分の集計ウィンドウが閉じたタイミングで (04分~08分が (5個) すべて条件を満たす最初のタイミングとなるため) 、インシデントが発生することになります。
一方、”at least once in 5分” で設定した場合は、NULL の影響をあまり受けません。違反判定時には、いずれかの値が閾値条件を満たせばよいため、間に NULL な集計ウィンドウが存在してもインシデントが発生します。先の図の場合は、01分の集計ウィンドウが評価されるタイミングでインシデントが発生します。
”at least once in N (time)” の場合は、実質的には最新の集計ウィンドウが閾値条件を満たすか否かで評価されます。
データ遅延以外で、NULL の影響を考慮しなければならないのは、情報収集のポーリングよりも集計ウィンドウ期間を短く設定してしまっている場合があります。
例えば、Synthetic monitoring による失敗を検知するアラートコンディションで、Synthetics のモニター実行は 5分ポーリングだが、集計ウィンドウが 1分であった場合、モニターが実行された時間の集計ウィンドウにだけ シグナル値が記録されることになります。

(00分と05分に Synthetics のモニターが実行されたため、値が存在する)
先の説明の通り “for at least 5分” (すべてのシグナル値が条件を満たす) で設定してしまっている場合は、値が存在しない (NULL値) の集計ウィンドウがあるため、インシデントが発生しません。
上記は Gap-filling strategy (ギャップ埋め) を ”Last known value” に設定するなどで回避することができます。ギャップ埋め は、値が存在しない集計ウィンドウに対して、あとから値を補完する機能です。
先の Synthetics の例を用いると、01分~04分のシグナル値は存在しませんでしたが、05分にデータが入り集計されたタイミングで、値が存在しなかった 01分~04分の値を固定値や直前値 (=00分のシグナル値) にして、アラートの評価に利用するという動作をします。

ギャップ埋め (Last known value) を設定すると上記の ”for at least 5分” の場合では、評価対象の 5個の集計ウィンドウすべてが閾値条件を満たす 10分の集計ウィンドウが閉じたタイミングでインシデントが発生することになります。
静的閾値設定における違反・回復の条件
ここまでで静的閾値の設定には、”at least once in” と “for at least” の 2種類あることを説明してきましたが、それぞれの回復条件についてもご紹介いたします。
結論から言えば、どちらの場合でも回復条件には差はなく、対象となる集計ウィンドウのすべてが閾値の条件を満たさなかった場合、回復判定となります。注意点としては “すべての集計ウィンドウ” が対象となるため、NULL が存在すると回復条件は満たされません。
対処方法としては、先と同じようにギャップ埋め (Last known value) を設定することで、NULL 値を補完し、回復条件を満たすことができるようになります。
それぞれの設定の違反・回復条件をまとめると下記となります。
- for at least N time
- 違反条件:
すべての期間で閾値を満たしたら違反が発生
(対象期間の集計ウィンドウデータに NULL が存在すると判定されない) - 回復条件:
すべての期間で閾値を満たさなかったら回復
(対象期間の集計ウィンドウデータに NULL が存在すると判定されない)
- 違反条件:
- at least once in N time
- 違反条件:
対象期間データのいずれかが閾値を満たせば、違反が発生
(対象期間の集計ウィンドウデータに NULL が存在しても判定される)
- 回復条件:
すべての期間で閾値を満たさなかったら回復
(対象期間の集計ウィンドウデータに NULL が存在すると判定されない)
- 違反条件:
NrAiSignal を用いたデータの確認
最後に、認識と異なりインシデントが違反や回復判定されなかった際の調査方法として、NrAiSignal を参照する方法をご紹介いたします。
NRQL を用いて、NrAiSignal イベントをクエリすることで各アラートコンディションで集計されたシグナルの詳細を確認することができます。
各集計ウィンドウの開始・終了時刻、記録されたシグナル値、対象となったデータポイント数など本ブログで紹介した内容もご確認することができます。
下記のように WHERE 句でコンディションID やシグナルID を指定することで、各時間の集計ウィンドウの値 (シグナル値) を追跡することができます。
SELECT * FROM NrAiSignal WHERE conditionId = コンディションID SINCE 3 hours ago
ただし、値が存在しなかった場合は、対象の時刻データが存在しないだけで NULL値と記録されているわけではないので、時刻が連続でない場合を NULL値と考える必要があります。
(下記ではデータが存在しない 03:53, 03:55, 03:57 などが NULL 値な集計ウィンドウとなります。)

NrAiSignal や NrAiIncident をクエリすることで、UI 上ではわかりにくい原因の調査を行うことができます。
まとめ
初期のアラート設定において、インシデントが発生しない、回復しないということがございましたら、一度、ゼロヌル問題に該当していないかご確認いただければと思います。
The views expressed on this blog are those of the author and do not necessarily reflect the views of New Relic. Any solutions offered by the author are environment-specific and not part of the commercial solutions or support offered by New Relic. Please join us exclusively at the Explorers Hub (discuss.newrelic.com) for questions and support related to this blog post. This blog may contain links to content on third-party sites. By providing such links, New Relic does not adopt, guarantee, approve or endorse the information, views or products available on such sites.