New Relicで発生したMGIの対応について
はじめに
私の関わるサービスでNew Relicを利用しているのですが、そこでMGI(Metrics Grouping Issue)が発生し、その対応を行うことがあったので、その時の事をお伝えしようと思います。
MGIとは?
以下、New Relicの公式ブログから抜粋となります。
MGIが発生すると、Metrics normalization に自動的に拒否ルールが作成されてしまい、新しいメトリクスが登録されなくなってしまいます。
このため、定期的にMGIの発生を監視し、発生時は対応する必要があります。
MGIの対応の流れ
対応方法はいろいろありますが、今回はアプリの修正などは行わずに、収集されたメトリクスを調整する方法をとりました。
ざっくりとした流れは以下のようになります。
Metrics normalizationでMGIが発生しているかを確認
MGIが検知されると、「DENY_NEW_METRICS」という新規メトリクスをリジェクトするルールが作成されます
詳細を確認すると noteの部分に下記のようなに自動作成された旨が記録されています
Autogenerated metric normalization deny-new-metrics rule : deny_new_metrics
MGI detailで詳細を確認し、問題と思われるメトリクスを特定する
見つけたメトリクスに対するMetrics normalization Ruleを作成し、集約(replace)または拒否(reject)を設定する
実際の対応例
上記だけではわかりずらいと思うので、実際の画面を加えながら今回実施した事を説明していきます。
なお、今回はAPMが収集しているメトリクスでMGIが発生していました。
Metrics normalization を選択
MGI details で詳細を確認
MGI troubleshooting で対象のメトリクスを確認
今回の例ではThreads/Stateが他に比べて多いことがわかります
メトリクスの詳細を確認
より詳細な状態を確認するためにNRQLを使います。
今回はAPMが対象なので、以下のようにappNameで絞り込みました。
FROM Metric SELECT metricTimesliceName
WHERE appName = 'xxxxxxx'
AND metricTimesliceName LIKE 'Threads/State%'
AND newrelic.timeslice.value IS NOT NULL
SINCE 60 MINUTES AGO LIMIT MAX
この結果から全体像の雰囲気を掴んでください。
集約するための正規表現を検証
まずはcaputreを利用してグルーピングして状況を確認してみます
発行したSOQLはこちらになります。
WHERE appName = 'xxxxx'
AND metricTimesliceName LIKE 'Threads/State%'
AND newrelic.timeslice.value IS NOT NULL
SINCE 60 MINUTES AGO LIMIT MAX
facet capture(metricTimesliceName, '(?P<metricName>Threads/[^/]+/[^- /]+).*')
他に比べて多いものがなんとく見えてきますね。
次は最も件数が多いThreads/State/MVStoreに絞って確認してみます
FROM Metric SELECT count(metricName)
WHERE appName = 'xxxxx'
AND metricTimesliceName LIKE 'Threads/State/MVStore%'
AND newrelic.timeslice.value IS NOT NULL
SINCE 60 MINUTES AGO LIMIT MAX
facet capture(metricTimesliceName, '(?P<metricName>Threads/[^/]+/[^/]+).*')
末尾に乱数が含まれていることがわかります。
なお、# となっている部分がありますが、これは数値の部分がNew Relic側で自動的に # に置き換えられているためです
乱数部分は情報として不要なので、以下のように置き換えてみます
# 元データ
MVStore background writer nio:-opt-xxxxxxxxxxxx-work-tmp-tmpslatdqg....
# 置換後データ
MVStore background writer nio
発行したNRQLはこちら
FROM Metric SELECT count(metricName)
WHERE appName = 'xxxxx'
AND metricTimesliceName LIKE 'Threads/State/MVStore%'
AND newrelic.timeslice.value IS NOT NULL
SINCE 60 MINUTES AGO LIMIT MAX
facet capture(metricTimesliceName, '(?P<metricName>Threads/State/MVStore [a-zA-Z ]+).*')
想定通りに集約されたことが確認できます
上記以外にも件数が多いものがありましたが、集約条件を探すまでの条件は同じであるため割愛します。
置換ルールを設定
これまでに確認した結果を元に、メトリクスを置換・集約するためのルールを登録します
今回は以下の内容で登録しました
Regular expression : (Threads/[^/]+/[/a-zA-Z]*MVStore [a-zA-Z ]+).*
What do you want to do with the matches? : Replace
Replacement : \1
MGIで作成されたルールを無効化する
新しいメトリクスを登録できるようにするため、自動作成されたルールを無効化します
MGI detailsを表示する際のメニューの中に Deactivate というものがあるので、それを選択することでルールを無効できます
結果を確認
新しいルールが適応された状態で暫く動作させたのち、集約されているかを下記のようなNRQLを実行して確認します。
FROM Metric SELECT uniqueCount(metricTimesliceName)
WHERE entity.guid = 'xxxxxxxx'
AND metricTimesliceName LIKE 'MVStore background writer %'
AND newrelic.timeslice.value IS NOT NULL
SINCE '2024-03-03 00:00:00 UTC' UNTIL NOW LIMIT 20 FACET host.displayName TIMESERIES
なお、発行するNRQLでmetricTimesliceNameのみを指定された場合は、1日程度はルール適用前のメトリクスが取得されてしまうという仕様があるそうなので注意してください。(現在は改善されている可能性もあります)
SELECT metricTimesliceName FROM Metric
最後に
今回は実際に行なった手順に沿って説明したつもりですので、まだMGIに遭遇したことがない方にも、うっすらとでも対応のイメージが湧いたのではないでしょうか。
今回の記事が皆様の関わっているシステムの安定運用の助けになれば幸いです。