NRQLマスターになろう - Metric編

オブザーバビリティを語る上で重要なMELT（メトリクス、イベント、ログ、トレース）。MELTのデータのうち、メトリクスのデータをNRQL (New Relic Query Language) を使って可視化・分析する方法をご紹介します。

# はじめに
New Relicを含むオブザーバビリティ関連ソリューションは、ITシステム全体から多様なデータを収集することで、システムの状態を深く把握し、問題の解決や改善をすることを可能にします。収集するデータは、一般的にはメトリクス、イベント、ログ、トレースというものに分類され、それぞれの頭文字をとってMLTやMELTと呼ばれています。

https://newrelic.com/jp/blog/how-to-relic/metrics-events-logs-and-traces



New Relicは、MELTを意識せずともその垣根を超えて分析しやすいUIをビルトインで提供していますが、MELTを理解することでより深く詳細な分析やアドホックな調査を行うことができるようになります。この記事では、MELTのデータのうちメトリクス（以降、Metric）について以下のような内容に触れながら解説します。

- Metricとは
- New RelicにおけるMetric
- Metricのデータ構造
- データの見方

# Metricとは
モニタリング業界において、Metric（メトリクス）とはアプリケーションやシステムに関する数値的な測定値を表すもの、というのが一般的な定義です。Metricには、ある一時点（タイムスタンプ）の数値データもあれば、ある期間で集約された集計データなどがあります。例えば、前者はとある時点でのCPU%で、集計データはある期間内の最大値や平均などが該当します。

事象ごとにレコードが作られるEvent（イベント）データと異なり、Metricは上記のように最大、最小、平均などの複数のフィールドを持ち、かつそれをまた集計できる点が特徴です。このような特性から、Metricは長期でデータを保存したり傾向をみたりする点に強みがあります。一方で、集約された過去データから詳細を深掘りするのには限界があるため、その場合は生データであるEvent（イベント）をうまく組み合わせていく形になります。

Metricの詳細については公式ドキュメントもご参照ください。

https://docs.newrelic.com/jp/docs/data-apis/understand-data/new-relic-data-types/#metrics


# New RelicにおけるMetric
New Relicには歴史的な背景もあり、Metricといった時に以下の2つが度々出てくることは頭の片隅においておくと良いです。

一つ目が、***Dimensional Metrics***です。Metric API (AWSなどのクラウド統合を含む)やOpenTelemetry、Prometheus Integrationなどを使って送られるMetricデータが基本的にこの形になります。数値データや集計期間に加え、様々な属性（Dimension, ディメンション）を持ちます。一般的にはMetricというとこちらを指すでしょう。

二つ目が、APMやBrowserなどのエージェントが従来から送っているMetricであり、***Metric timeslice data***と呼ばれています。Metric timeslice dataはDimensional Metricsとはデータの持ち方、保存期間、クエリの仕方などが異なります。

この記事では主にDimensional Metricsの方に焦点を当てます。Dimensional Metrics以外のものも含め、New RelicのMetricに関する詳細については以下の公式ドキュメントをご参考にしてください。

https://docs.newrelic.com/jp/docs/data-apis/understand-data/new-relic-data-types/#metrics-new-relic




なお、一部のMetric timeslice dataは自動的にDimensional Metricsに変換されたりするのでNRQLでDimensional Metricsのようにクエリすることもできます。ただし、***Metric timeslice dataがDimensional Metricsとして認識されていない場合や、Metric timeslice dataを取るためのクエリには特有の制約もあります***。その辺りの詳細は以下のドキュメントをご参照ください。

https://docs.newrelic.com/jp/docs/data-apis/understand-data/metric-data/query-apm-metric-timeslice-data-nrql/

# Metricの種類
Metricはそのデータや集計方法の特徴によって種類が異なりますが、New Relicでは以下のような種類（Metric type）があります。

<table>
  <thead>
    <tr>
      <th>種類</th>
      <th>説明</th>
      <th>使える集計関数</th>
    </tr>
  </thead>
  <tr>
    <td>count</td>
    <td>何らかの事象の発生回数を表します。例えば一定期間のキャッシュヒット回数などです。Metricがレポートされるたびに0でリセットされる点が特徴です。</td>
    <td>sum</td>
  </tr>
  <tr>
    <td>cumulativeCount</td>
    <td>事象の発生回数である点はcountと同様ですが、サーバーやアプリケーションが再起動されて0にリセットされるまで増える点が違いです。いわゆる累積メトリクスです。</td>
    <td>sum</td>
  </tr>
  <tr>
    <td>gauge</td>
    <td>時間と共に増減する値を表します。例えば、温度、CPU使用率、メモリ使用率などです。</td>
    <td>latest<br>min<br>max<br>sum<br>count<br>average</td>
  </tr>
  <tr>
    <td>distribution</td>
    <td>数値属性の統計的分布を追跡します。他のソリューションだとhistogramに該当するでしょう。</td>
    <td>percentile<br>histogram<br>min<br>max<br>sum<br>count<br>average</td>
  </tr>
  <tr>
    <td>summary</td>
    <td>distributionと似ていますが、summaryは事前に集計されたデータ、または集計された個別イベントの情報を報告するために使用される。例としては、トランザクション数/持続時間、キュー数/持続時間などがあります。</td>
    <td>min<br>max<br>sum<br>count<br>average</td>
  </tr>
  <tr>
    <td>uniqueCount</td>
    <td>文字列または数値属性の一意な値の数を追跡する。</td>
    <td>uniqueCount</td>
  </tr>
</table>

Metricの種類の詳細については以下の公式ドキュメントをご参照ください。

https://docs.newrelic.com/docs/data-apis/understand-data/metric-data/metric-data-type/

また、OpenTelemetryやPrometheusなどのツールにより計装されたMetricがNew Relicに統合した際に、どの種類のMetricにマッピングされるかについては以下のドキュメントに詳細がありますのでこちらもご確認ください。

https://docs.newrelic.com/jp/docs/opentelemetry/best-practices/opentelemetry-best-practices-metrics/

https://docs.newrelic.com/jp/docs/data-apis/understand-data/metric-data/cumulative-metrics/

---

では、NRQLを使ってMetricのデータをみてみましょう。

# Metricに対するクエリの基本形
NRQLを使ってMetricデータを参照する場合は基本的には以下のような形になります。送信するデータの種類ごとにネームスペースの異なるイベントデータとは異なり、Metricの場合はFROMに書くのは全てMetricです。SELECT句では集約関数(function)を使ってMetricの値をみたい観点で抽出し、WHERE句でディメンションによる絞り込みをかけたり、FACET句でディメンションによるグルーピングしたりできます。TIMESERIESなど足すと時系列に表示できます。

```sql:Metricデータを見るNRQLの基本形
FROM Metric 
SELECT function(metric_name) 
WHERE attribute=value 
FACET attribute 
```

たとえば、アプリケーションごとのレスポンスタイムの平均をMetricを使って見る場合は以下の通りです。

```sql:アプリケーションごとのレスポンスタイムの平均を取るNRQL
FROM Metric 
SELECT average(newrelic.goldenmetrics.apm.application.httpResponseTimeMsMetric) 
FACET entity.name 
```

# Metricの種類を確認してみる
Metricの種類によって使える関数が異なるということは上記の通りですが、収集しているMetricがどのような種類かはクエリで確認することができます。

例えば、summaryタイプのMetricにどのようなものがあるかは以下のクエリで確認することができます。summaryの部分を変えればguageやdistributionも同様に調べることができます。（ちなみに%は、複数種類のMetricを一度にクエリの対象にする時のワイルドカードです）

```sql:summaryタイプのMetric一覧を取得するNRQL
FROM Metric 
SELECT uniques(metricName) 
WHERE getField(%, type) = 'summary'
```

以下のような感じで取得できました。Metricの中にはNew Relicが生成するものもあれば、PrometheusやOpenTelemetryなどで収集したものもあります。

![Metric Type-summary.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535230/ef3cf2d1-1646-9e90-0200-e0dd678ecc39.png)



次に、特定のMetricがどのタイプかを調べるNRQLです。例えば、以下のようなクエリで抽出できます。ここではmetricNameがkubelet_から始まるMetricを全て対象にし (%はワイルドカード)、FACETでMetric名と種類を指定することで組み合わせごとに表示されるようにしています。

```sql:Metricのタイプを取得するNRQL
FROM Metric 
SELECT count(*) 
WHERE metricName like 'kubelet_%' 
FACET metricName, getField(%, type) LIMIT max
```

![MetricType-kubelet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535230/66f157fb-f4ab-9278-2a4b-71bfabc1ccfe.png)


これでどのMetricがどの種類かが確認できました。maxやaverageなどの集計関数を使っているのに結果が返ってこないような場合は、一度Metricの種類と使える関数を確認すると良さそうです。

# Metricのデータを確認する
さて、Metricの種類が確認できたので実際にどのようなデータが入っているかを確認してみましょう。

```sql:Metricの生データを確認
FROM Metric 
SELECT * 
WHERE metricName='kubelet_container_log_filesystem_used_bytes'
```

この例では、guageタイプのkubelet_container_log_filesystem_used_bytesをみてみます。色々なディメンションがありますが、赤枠の部分が実際の数値データです。guageタイプであること、guageタイプなのでmin/max/countなどのデータがまとまって入っていることがわかります。ここがMetricのデータの特徴ですね。

![metric_raw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535230/ee006f2c-2696-f1b8-daf5-f01ce2324a78.png)


特定のMetricに対してどのようなディメンションがあるか確認したい場合はkeyset()やdimensions()関数が使えます。
```sql:Metricのディメンションを確認
FROM Metric 
SELECT keyset() 
WHERE metricName='kubelet_container_log_filesystem_used_bytes'
```

![Metric - dimension.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535230/d3abb15d-a43a-4a2c-7ae1-b0ce1fefe228.png)


あとは、冒頭で説明した基本形に則り、好きな集計関数を使ってNRQLを書くだけです。例えばkubelet_container_log_filesystem_used_bytesというMetricの最大値と平均を時系列で表示するクエリは以下の通りとなります。

```sql:Metricの最大 (max) と平均 (avegage)を取得するクエリ
FROM Metric 
SELECT max(kubelet_container_log_filesystem_used_bytes), 
       average(kubelet_container_log_filesystem_used_bytes) 
TIMESERIES 
```

![Metric Query.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535230/820d5353-b854-66ad-aefb-d0a89e2e6146.png)


# 絞り込み条件や別関数で利用する: getField関数
先ほどの例ではSELECTでmaxやaverageなどの集計関数を利用することでMetricデータから該当の値を取得して表示できることを示しました。

一方、Metricの値をWHERE句の絞り込み条件で利用したり、Metricの値を別の関数に渡したい場合にはgetField関数を利用する必要があります。

***getField関数は、複数のフィールドを持つMetricデータから特定のデータを抽出するための関数***で、基本的な構文は```getField(metricName, field)```、もしくは```metricName[field]```となります。



例えば、```getField(kubelet_container_log_filesystem_used_bytes, max)```だと、kubelet_container_log_filesystem_used_bytesというMetricのmax値を抽出できます。

### Metricの値で絞り込む
以下のクエリはトランザクションのレスポンスタイムの平均をアプリケーションごとに出すクエリです。WHERE句でトランザクション数が一定数 (1000件) 以上のものに絞り込んでいますが、その際getFieldにてcountフィールドを抽出して比較しています。

```sql:WHERE句でMetricの値で絞り込む
FROM Metric 
SELECT average(apm.service.transaction.duration) 
WHERE getField(apm.service.transaction.duration, count) > 1000 and appName like '%' 
FACET appName
```

なお、```getField(apm.service.transaction.duration, count) > 1000```の部分は```apm.service.transaction.duration[‘count’] > 1000```という書き方でも大丈夫です。

※ apm.service.transaction.durationは、実は冒頭で説明したMetric timeslice dataなので仕様上WHERE句でappNameなどで対象を絞る必要があるのでそのようなクエリになっています。

### SELECTでMetricの値を組み合わせる
以下のクエリはアプリケーションのトランザクションのエラー率を出すクエリです。SELECT句で指定している値の分母は発生したトランザクション数の合計。分子は、そのうちエラーが発生した回数の合計です。エラーの発生数は、apm.service.error.countというMetricの値をsum関数で合計しています。その際、getFieldにてcountフィールドを抽出しています。

```sql:SELECT句の関数内でMetricの値を使う
SELECT sum(getField(apm.service.error.count, count)) / count(apm.service.transaction.duration)  
FROM Metric 
WHERE appName like '%' 
FACET appName
```

先ほどと同様に```getField(apm.service.error.count, count)```の部分は、```apm.service.error.count[‘count’]```とすることも可能です。

※ apm.service.transaction.durationやapm.service.error.countは、実は冒頭で説明したMetric timeslice dataなので仕様上WHERE句でappNameなどで対象を絞る必要があるのでそのようなクエリになっています。


getField関数の詳細は公式ドキュメントをご参照ください。

https://docs.newrelic.com/jp/docs/nrql/nrql-syntax-clauses-functions/#func-getfield


# カーディナリティ
Metricを扱う際はカーディナリティとの付き合っていくことも重要なポイントです。一般的に、カーディナリティとはディメンションとその値のセットのバリエーションの多さを表しますが、カーディナリティが高ければ詳細にデータを分析できる反面、データの保存や検索の効率が下がりコストがかかるというトレードオフがあります。また、New Relicにもカーディナリティの上限があるので注意が必要です。

Metricのカーディナリティは以下のNRQLで確認可能です。ポイントはロールアップされる前のデータを確認するためにRAWを入れる点です。

```sql:カーディナリティの高いMetricを特定する
FROM Metric SELECT cardinality() FACET metricName since today RAW
```

もしくは、特定のMetricのカーディナリティを確認したい場合はMetric名を指定することもできます。
```sql:特定のMetricのカーディなリティを確認する
FROM Metric SELECT cardinality(<Metric名>) since today RAW
```

この他、カーディナリティの上限に達したことが原因でエラーが出ている場合は、NrIntegrationErrorというイベントにその情報が格納されるのでそれで確かめることができます。

カーディナリティの管理については以下のドキュメントをご参考にしてください。

https://docs.newrelic.com/jp/docs/data-apis/ingest-apis/metric-api/NRQL-high-cardinality-metrics/

https://newrelic.com/jp/blog/how-to-relic/manage-prometheus-cardinality

https://docs.newrelic.com/jp/docs/data-apis/ingest-apis/metric-api/cardinality-management/


# まとめ
簡単ではありますが、New Relicで扱うデータのうちMetricについてその特徴とデータの見方について解説しました。Metric以外のイベント、ログ、トレースをうまく組み合わせながら分析することが現状把握や問題の原因特定を早めますので簡単なクエリから始めてみてください。

なお、現状Metricとして保存されていないデータをMetricにする方法もあります。それに関しては以下のドキュメントをご参考にしてください。

https://docs.newrelic.com/jp/docs/data-apis/convert-to-metrics/analyze-monitor-data-trends-metrics/

# その他
New Relicでは、**新しい機能やその活用方法**について、QiitaやXで発信しています！
**無料でアカウント作成**も可能なのでぜひお試しください！

:::note info
New Relic株式会社の[X(旧Twitter)](https://x.com/NewRelicJapan) や [Qiita OrganizationOrganization](https://qiita.com/organizations/newrelic)では、
新機能を含む活用方法を公開していますので、ぜひフォローをお願いします。
:::

:::note info
無料のアカウントで試してみよう！
[New Relic フリープランで始めるオブザーバビリティ！](https://qiita.com/ktst79/items/5ee74b34e6adb8a7a6fa)
:::

### NRQLマスターになろうシリーズはこちら

https://qiita.com/ktst79/items/c1ddf33e18e9cfeba893

https://qiita.com/ktst79/items/5d84d6a2ceca90efa108

https://qiita.com/ktst79/items/56e49f71487928c5bca1

https://qiita.com/ktst79/items/f743ad2207c435134615