> Source: https://www.ymotongpoo.com/works/oteps/metrics/otep-0113/


# OTEP-0113: メトリクスとエグゼンプラーの統合

本OTEPは、メトリクスSDKで定義される集約にエグゼンプラーのサポートを追加します。

## 定義 {#definition}

エグゼンプラーは、集約されたデータのサンプルとなるデータポイントです。
エグゼンプラーは、そうでなければ一般的な集約に、具体的なコンテキストを提供します。
ヒストグラム型のメトリクスでは、エグゼンプラーはヒストグラムの各バケットに関連付けられたポイントであり、そのバケットに集約された内容の一例を示すものです。
エグゼンプラーは、計測値そのものにとどまらず、その計測が記録されたサンプリング済みトレースへの参照と、その計測に付与されたラベルによって拡張されます。

## 動機 {#motivation}

集約に対するエグゼンプラーの振る舞いを定義することで、OpenTelemetryはGoogle Cloud Monitoringにおけるエグゼンプラーをサポートできるようになります。

エグゼンプラーは、メトリクスとトレースの間をつなぐリンクを提供します。
高QPSなサーバーの応答レイテンシーを時系列で追跡するために、あるユーザーがヒストグラム集約を使っている場合を考えてみましょう。
このヒストグラムはリクエストの速さに基づくバケットで構成されており、たとえば「400〜500ミリ秒かかったリクエストが55件あった」という形になります。
ユーザーは遅いリクエストのトラブルシューティングをしたいので、レイテンシーが高かったトレースを見つける必要があります。
エグゼンプラーがあれば、ユーザーは高レイテンシーのバケットからエグゼンプラーとなるトレースを、低レイテンシーのバケットからもエグゼンプラーとなるトレースを取得でき、それらを比較して高レイテンシーの原因を突き止めることができます。

エグゼンプラーは、関連するトレースが集約により多くのコンテキストを提供できる場合、そして集約では他の方法では表示されない具体的な情報（たとえば、集約によって失われてしまう可能性のあるラベルの完全な集合）をエグゼンプラーが示せる場合において、あらゆる集約にとって意味を持ちます。

## 内部の詳細 {#internal-details}

エグゼンプラーは `RawValue` であり、次のように定義されます。

```
message RawValue {
  // Numerical value of the measurement that was recorded. Only one of these two fields is
  // used for the data, depending on its type
  double double_value = 0;
  int64 int64_value = 1;
  
  // Exact time that the measurement was recorded
  fixed64 time_unix_nano = 2;

  // 'label:value' map of all labels that were provided by the user recording the measurement
  repeated opentelemetry.proto.common.v1.StringKeyValue labels = 3;

  // Span ID of the current trace
  optional bytes span_id = 4;

  // Trace ID of the current trace
  optional bytes trace_id = 5;

  // When sample_count is non-zero, this exemplar has been chosen in a statistically
  // unbiased way such that the exemplar is representative of `sample_count` individual events
  optional double sample_count = 6;
}
```

エグゼンプラーの収集は、オプションのパラメーターによって有効化できるようにするべきで、デフォルトでは無効にするべきです。
また、有効化されていない場合には、エグゼンプラーに関連する収集や処理は一切行われるべきではありません。
これは、必要な場合にアグリゲーターができる限り高いパフォーマンスを発揮できるようにするためです。
アグリゲーターはまた、サンプリングされたトレース中に記録された場合にのみエグゼンプラーを収集するのか、それともトレーシングがどのエグゼンプラーがサンプリングされるかに一切影響しないようにするのかを決定するためのパラメーターも持つべきです。
これにより、必要に応じて、メトリクスとトレースの間のリンクとエグゼンプラーの統計的な有意性のどちらを優先するかを、集約側で選べるようになります。

[#347](https://github.com/open-telemetry/opentelemetry-specification/pull/347) では、メトリクスSDKにおける一連の標準的なアグリゲーターについて説明しています。
ここでは、それぞれのアグリゲーターに対してエグゼンプラーをどのように実装できるかを説明します。

### 標準的なアグリゲーターにおけるエグゼンプラーの挙動 {#exemplar-behaviour-for-standard-aggregators}

#### HistogramAggregator {#histogramaggregator}

HistogramAggregatorは（有効化されている場合）、ヒストグラムの全バケットにわたって分布するエグゼンプラーのリストを保持しなければなりません（MUST）（サンプリング可能な計測値が1つ以上あるすべてのバケットには、1つ以上のエグゼンプラーが存在するべきです）。
実装は、エグゼンプラーの数を無制限に保持するべきではありません（SHOULD NOT）。

#### Sketch {#sketch}

Sketchアグリゲーターは、分布全体にわたって間隔を空けて配置されたエグゼンプラーのリストを保持するべきです（SHOULD）。
保持すべきエグゼンプラーの具体的な数は決まっていませんが（ただし、その数を無制限にするべきではありません（SHOULD NOT））、実装は分布をできる限り広くカバーするエグゼンプラーを選ぶべきです（SHOULD）。
（具体的な詳細は未定義であり、未解決の課題を参照してください。）

#### Last-Value {#last-value}

ほとんど（あるいはすべて）のLast-Valueアグリゲーターは非同期に動作し、コンテキストとやり取りすることはありません。
Last-Valueの値は最後の計測値そのもの（本質的にエグゼンプラーの他の構成要素に相当します）であるため、Last-Valueに対してエグゼンプラーを実装する価値はありません。

#### Exact {#exact}

Exactアグリゲーターは、エグゼンプラーが持つすべての情報を含む `RawValue` のリストを保持することで機能します。
したがって、Exactアグリゲーターはエグゼンプラーを保持する必要がありません。

#### Counter {#counter}

エグゼンプラーは、2つの点でCounter集約に価値を与えます。
1つは、メトリクスとトレースのデータを結び付けることであり、もう1つは、入力の分布を再構成するために必要な情報を提供することです。
有効化されている場合、アグリゲーターは各チェックポイントで、データの分布全体からサンプリングされた、有限個数のエグゼンプラーのリストを保持します。
エグゼンプラーは統計的に有意な方法でサンプリングされるべきです。

#### MinMaxSumCount {#minmaxsumcount}

Counterと同様に、MinMaxSumCountも、統計的に有意な方法で入力の分布全体からサンプリングされた、有限個数のエグゼンプラーのリストを保持するべきです。

#### カスタムアグリゲーター {#custom-aggregators}

カスタムアグリゲーターは、エクスポーターが取得できるエグゼンプラーのリストを保持することで、エグゼンプラーをサポートしてもかまいません（MAY）。
カスタムアグリゲーターは、接続されたエクスポーターでの用途に基づいてエグゼンプラーを選択するべきです（たとえば、Google Cloud Monitoring向けに記録されたエグゼンプラーは、サンプリングされたトレース内で記録された場合にのみ保持されるべきです）。

エグゼンプラーは、常にアグリゲーションから（エクスポーターによって）RawValueオブジェクトのリストとして取得されます。
これらは、`Metric` オブジェクト上の

```
optional repeated RawValue exemplars = 6
```

という属性を介してやり取りされます。

## トレードオフと緩和策 {#trade-offs-and-mitigations}

エグゼンプラーを実装する上での主な懸念は、パフォーマンス（メモリ使用量、そしてある程度は時間計算量の面で）です。
しかし、エグゼンプラーの記録をオプションにすることで、エグゼンプラーが有効化されていないときのオーバーヘッドは最小限に抑えられるはずです。

## 先行技術と代替技術 {#prior-art-and-alternatives}

エグゼンプラーは[OpenCensus](https://github.com/census-instrumentation/opencensus-specs/blob/master/stats/Exemplars.md#exemplars)で実装されていますが、HistogramAggregatorに対してのみです。
本OTEPは主にOpenCensusにおけるエグゼンプラーの定義を移植したものですが、他のアグリゲーターに対してもエグゼンプラーのサポートを追加しています。

[エグゼンプラーに関するCloud Monitoring APIドキュメント](https://cloud.google.com/monitoring/api/ref_v3/rpc/google.api#google.api.Distribution.Exemplar)

## 未解決の課題 {#open-questions}

- エグゼンプラーは通常、サンプリング済みトレース内のスパンを参照します。
  コレクターを使ってテールサンプリングを行っている場合、サンプリングの判断がメトリクスのエクスポート後まで先送りされることがあります。
  このような場合、どのようにエグゼンプラーを作成すればよいでしょうか。

- 私たちは、Sketchアグリゲーターが実装の観点でどのように動作するかについて強い理解を持っていません。
  そのため、エグゼンプラーが正しく機能する方法を設計するための十分な情報がありません。

- 仕様はまだ標準的な集約の集合を定義しておらず、標準的なメトリクス計装器に対するデフォルトの集約を定義しているだけです。
  エグゼンプラーは常に特定の集約に紐づくものであるため、エグゼンプラーの挙動を完全に規定することはできません。

