メトリクス

実行時に取得された測定値

メトリクスとは、実行時に取得されるサービスの測定値のことです。 測定値を取得した瞬間はメトリクスイベントとして知られており、測定値そのものだけでなく、キャプチャした時刻と関連するメタデータから構成されます。

アプリケーションとリクエストのメトリクスは、可用性とパフォーマンスの重要な指標です。 カスタムメトリクスは、可用性指標がユーザー体験やビジネスにどのような影響を与えるかについての洞察を提供できます。 収集したデータを使用して、障害を警告したり、需要が高まったときにデプロイを自動的にスケールアップするスケジューリング決定をトリガーしたりできます。

OpenTelemetryのメトリクスがどのように機能するのかを理解するために、コードの計装の一部を担うコンポーネントのリストを見てみましょう。

メータープロバイダー

メータープロバイダー(MeterProvider と呼ばれることもあります)は、Meterのファクトリーです。 ほとんどのアプリケーションでは、メータープロバイダーは一度だけ初期化され、そのライフサイクルはアプリケーションのライフサイクルと一致します。 メータープロバイダーの初期化には、リソースとエクスポーターの初期化も含まれます。 これは通常、OpenTelemetryを使った計測の最初のステップです。 いくつかの言語SDKでは、グローバルなメータープロバイダーがすでに初期化されています。

メーター

メーターはメトリクス計装を作成し、実行時にサービスに関する測定値を取得します。 メーターはメータープロバイダーから作成されます。

メトリクスエクスポーター

メトリクスエクスポーターはメトリクスデータをコンシューマーに送ります。 このコンシューマーは、開発中のデバッグのための標準出力、OpenTelemetryコレクター、あるいは、あなたが選んだオープンソースやベンダーのバックエンドです。

メトリクス計装

OpenTelemetryでは、計測は メトリクス計装 によって行われます。メトリクス計装は以下のように定義されます。

  • 名前
  • 種類
  • 単位(オプション)
  • 説明(オプション)

名前、単位、説明は、開発者が自分で定義するか、リクエストやプロセスメトリクスのような一般的なものについては、セマンティック規約を介して定義されます。

計装の種類は以下のいずれかです。

  • Counter(カウンター): 時間とともに蓄積される値。これは車のオドメーターのようなものだと考えられます。
  • Asynchronous Counter(非同期カウンター)カウンター と同じですが、各エクスポートに対して一度だけ収集されます。 連続したインクリメントにアクセスできず、集約された値のみにアクセスできる場合に使用できます。
  • UpDownCounter(アップダウンカウンター): 時間の経過とともに蓄積されるけれども、減少することもある値。 たとえば、キューの長さは、キュー内のワークアイテムの数によって増減します。
  • Asynchronous UpDownCounter(非同期アップダウンカウンター): アップダウンカウンターと同じですが、各エクスポートに対して一度だけ収集されます。 連続的な変更にアクセスできず、集約された値(たとえば、現在のキューのサイズ)のみにアクセスできる場合に使用できます。
  • Gauge(ゲージ): 読み取った時点での現在の値を測定します。たとえば、自動車の燃料計など。ゲージは同期しています。
  • Asynchronous Gauge(非同期ゲージ): ゲージと同じですが、各エクスポートに対して一度だけ収集されます。 連続的な変更にアクセスできず、集約された値のみにアクセスできる場合に使用できます。
  • Histogram(ヒストグラム): リクエストのレイテンシーなどの値をクライアント側で集約したもの。 値の統計に興味がある場合は、ヒストグラムが良いでしょう。 たとえば、どれくらいのリクエストが1秒未満か、といった疑問に答えてくれます。

同期と非同期の計装、またどの種類の計装があなたのユースケースにもっとも適しているかについては、補足ガイドラインを参照してください。

集約(アグリゲーション)

メトリクス計装に加えて、**集約(アグリゲーション)**という概念も理解すべき重要なものです。 集約とは、多数の測定値を組み合わせて、ある時間ウィンドウの間に発生したメトリクスイベントに関する正確な統計値または推定統計値にする手法です。 OTLPプロトコルは、このような集約されたメトリクスを伝送します。 OpenTelemetry APIは、各計装に対してデフォルトの集約を提供します。これはビューを使ってオーバーライドできます。 OpenTelemetryプロジェクトは、ビジュアライザーやテレメトリーバックエンドでサポートされるデフォルトの集計を提供することを目指しています。

リクエストトレースが、リクエストのライフサイクルを捕捉し、リクエストの個々の部分にコンテキストを提供することを意図しているのとは異なり、メトリクスは、集約された統計情報を提供することを意図しています。 メトリクスの使用例には、次のようなものがあります。

  • プロトコルの種類ごとに、サービスによって読み取られた総バイト数を報告する。
  • 読み込んだ総バイト数とリクエストごとのバイト数を報告する。
  • システムコールの継続時間を報告する。
  • 傾向を把握するためにリクエストサイズを報告する。
  • プロセスのCPUまたはメモリ使用量を報告する。
  • 口座の平均残高値を報告する。
  • 現在処理中のアクティブなリクエストを報告する。

ビュー

ビューは、SDKによって出力されるメトリクスをカスタマイズする柔軟性をSDKのユーザーに提供します。 どのメトリクス計装を処理するか、または無視するかをカスタマイズできます。 また、集約をカスタマイズしたり、メトリクスにどのような属性をレポートするかをカスタマイズすることもできます。

カーディナリティ制限

メトリクスのカーディナリティとは、そのメトリクスについて報告されるユニークな属性の組み合わせの数です。 SDKはユニークな組み合わせごとに個別の集約状態(データポイント)をメモリに保持するため、カーディナリティはメトリクスのメモリコストを左右します。 ログとは異なり、このコストはリクエスト量ではなく、ユニークな属性の組み合わせの数に応じてスケールするため、ユーザー IDや生の URLパスなどの高カーディナリティ属性は、メモリ使用量の際限のない増加を引き起こす可能性があります。

これに対する保護として、OpenTelemetryメトリクス SDKはカーディナリティ制限を強制します。 これはメトリクスストリームごとに追跡されるユニークな属性の組み合わせの最大数です。 デフォルト値は2000で、ビューでオーバーライドできます。

制限に達した場合、追加の属性の組み合わせが完全に破棄されるわけではありません。 かわりに、それらの測定値は属性 otel.metric.overflow=true で識別される単一のオーバーフローデータポイントに集約されます。 この設計には3つの重要な特性があります。

  • 測定値は失われない。 破棄されるのは属性のみです。 記録された値はオーバーフローデータポイントに集約されるため、メトリクスの全体的な合計は正確なままです。
  • メモリが制限される。 SDKは設定された数を超える組み合わせを追跡しません。
  • オーバーフローが観測可能である。 すべての SDKが同じ otel.metric.overflow=true マーカーを使用するため、単一のクエリでサービス、言語、バックエンドを横断してオーバーフローを検出できます。

トレードオフとして、オーバーフローしたメトリクスに対して属性でフィルタリングまたはグループ化するクエリは過少にカウントされます。 オーバーフローに集約された測定値はその属性を持たなくなるためです。

これは過小評価しやすい問題です。 オーバーフローは高カーディナリティ部分だけでなく、属性の組み合わせ全体を置き換えるためです。 たとえば、リクエストカウンターが url.path(高カーディナリティ)と success(真偽値)を一緒に記録しているとします。 ストリームがオーバーフローすると、{url.path=/checkout, success=false} の測定値は単一のオーバーフローデータポイント {otel.metric.overflow=true} に集約され、url.path とともに success も失われます。 success=false のクエリはその測定値を見逃しますが、success 自体は属性としてこれ以上なく低カーディナリティです。 success=false に基づくエラーレートアラートはそのため発火しなくなる一方、メトリクスの全体的な合計は正確なままです。

制限が適用されないもの

カーディナリティ制限が適用されるのは、メトリクス APIを通じて測定値を記録する際に提供される属性のみです。 以下には適用されません

  • service.nameservice.instance.id などのリソース属性。
  • メーターの作成時に設定される計装スコープ属性。

リソースおよび計装スコープ属性の値は、オーバーフローデータポイントを含むすべてのデータポイントに記録されるため、オーバーフロー中でも確実にクエリ可能です。 これは制限を回避するために測定属性をリソースに移動する理由にはなりません。 属性は、それが何を記述するかに従って配置すべきです。 リソースはテレメトリーを生成するエンティティを記述し、計装スコープは計装ライブラリを記述し、測定属性は個々の測定を記述します。 属性がこのようにモデル化されている場合、サービス名、環境、リージョンなど、プロセスの存続期間にわたって一定のコンテキストは、当然リソースに属し、オーバーフロー中でもクエリ可能なままです。

テンポラリティとカーディナリティ制限

同期計装の場合、集約テンポラリティはSDKが集約状態をどれだけ早く回収できるか、したがって制限にどれだけ早く達するかを決定します。

  • デルタテンポラリティでは、SDKは各サイクル後に状態をリセットするため、制限は単一サイクル内でアクティブな組み合わせのみを制約します。
  • 累積テンポラリティでは、SDKはサイクルをまたいで状態を保持するため、制限に達すると、プロセスが再起動するまで新しい組み合わせはオーバーフローし続けます。

非同期計装はこの概要の範囲を超える異なるルールに従います。

言語サポート

メトリクスはOpenTelemetry仕様のstableシグナルです。 Metrics APIとSDKの各言語固有の実装については、ステータスは以下の通りです。

LanguageMetrics
C++Stable
C#/.NETStable
Erlang/ElixirDevelopment
GoStable
JavaStable
JavaScriptStable
PHPStable
PythonStable
RubyDevelopment
RustBeta
SwiftDevelopment

仕様

OpenTelemetryのメトリクスの詳細については、メトリクス仕様を参照してください。