監視データの特性 - 分散トレースのサンプリング

## はじめに
こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。

この投稿は **[<font color="#6495ED">AoTo Advent Calendar 2024</font>](https://qiita.com/advent-calendar/2024/aoto) 13日目**の記事です。

オブザーバビリティで[主要なシグナル](https://github.com/cncf/tag-observability/blob/main/whitepaper.md#observability-signals)とされる**メトリクス・ログ・トレース**はそれぞれ異なる特徴を持ったテレメトリーシグナル(監視データ)です。それぞれの目的・データ形式・運用上の課題・データ特性を考慮して、オブザーバビリティを拡大することが重要です。

今回はその中でも「**分散トレースのサンプリング**」に焦点を当てて解説します。

解説ではオブザーバビリティの共通認識としてまとめられている **CNCF Tag Observability** の『[**Observability Whitepaper**](https://github.com/cncf/tag-observability/blob/main/whitepaper.md)』、標準化の例として **OpenTelemetry**/**Jaegar**・製品ベンダーの例として **Datadog** の公式ドキュメントを参考に解説を行います。

### 考慮事項
本投稿では以下の用途で表現を使い分けます。

- **監視情報**: 後述のテレメトリーシグナルとそれから得られた分析情報などを含む、監視に関わる全てのデータ
- **監視データ**: 人間が機械の動きを推測できるシステムの出力
- **トレース**: アプリケーションがリクエストの処理を追跡するために使用される監視データ、1つ以上の親子関係のあるスパンの集合
- **スパン**: 特定の期間における分散システムの論理的な作業単位、複数のスパンの集合がトレースとなる

## トレースの特徴
トレースは比較的新しく登場した監視データの一つです。
マイクロサービス化によって複数のサービス間で役割を分割したアーキテクチャが登場すると、保守性が向上するのと引き換えに問題発生時の原因分析が複雑となりました。こうした背景から登場した監視手法が分散トレースです。

トレースデータ自体は新しいデータタイプではなく、複雑な構造をしていません。トレースは特定のリクエスト処理の開始と終了を記録するスパンの集合体です。スパンは `json` 形式で、処理の名前・種別・開始/終了時のタイムスタンプ・任意の属性を持ち、一意の `Trace ID`, `Span ID`, 親 `Span ID` が割り当てられます。こうして関連するスパンを集約することで、複数のスパンはトレースとして可視化できます。

このことからも、トレース・スパンは `json` 形式で記録する構造化ログの一種に分類できます。ただし、ログよりも厳格に構造が定められており、**OpenTelemetry** を中心に **Trace Context** や **Span Context** などのスキーマが定められています。

:::note info
こうしたトレースの特性について、CloudNative Days Summer 2024 プレイベント in 東京でお話ししているので、是非ご覧ください🐶
:::

https://speakerdeck.com/aoto/understanding-distributed-tracing-trace-context-tabul-anatomic

ログの一種でありながら複雑な特性を持つトレースは、その革新性から独立した監視データとしての地位を確立しています。

![instrument_and_visualize_spans.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/427b436c-5606-6380-e461-621a04303930.png)

さらに、トレースは下記のような特徴を持ちます。
 - 単一トレースに含まれるスパンは異なるサービスから生成されることが多い
 - 異なるサービス毎にスパンの生成と転送を行い、バックエンドで単一のトレースとして可視化する
 - サービス間の通信にトレース識別子(`Trace Contex`)を伝搬する仕組みを組み込む必要がある
 - 各処理を記録するスパンを生成するため、記録するデータ量が膨大になる

このように、可視化バックエンドに到達するまでトレースは不完全な個々のスパンに分割されているのにも関わらず、それぞれの記録量が膨大となる傾向があります。そのため、繰り返される処理を全て記録・保管する必要はなく、ある処理を代表するトレースをある程度保管し、異常な動作をした際には必ず記録されるような仕組みが必要です。

## トレースのサンプリング
トレースのデータ量が膨大となる点は、ログの特性と共通しています。そのため、ログと同様に保管するトレースを分類できることが望ましいですが、ログと違いトレースは複数のスパンの集合である点により、異なるアプローチで膨大なデータ量に対処します。

ここで利用されるのが「サンプリング」です。繰り返される処理を全て記録・保管しないためにも、記録時に確率的に記録の有無を決定したり、保管時に同質なトレースをランダム抽出する方法が考えられます。さらに、特異な処理を記録したりエラー発生を記録したトレースはこうした方法に関わらず必ず記録する仕組みが必要とされます。

## プラクティス
こうしたサンプリングの手法と違いを正しく理解し、効果的な分析を行うためのトレースを常に可視化できる状態にしておくことが重要です。サンプリングにはどのような手法が存在し、それぞれどのような考慮事項があるかを考えていきましょう。

### ヘッドベースサンプリング
ヘッドベースサンプリングは、スパンの生成を確率的または条件に応じてサンプリングする手法です。

一般的に繰り返される処理は確率的にサンプリングを行う一方、特異な処理やエラーが発生した場合には異なる条件で記録を強制するような仕組みが求められます。

OpenTelemetry の場合、[確率サンプリング](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#non-probability-sampler)は統計的な計算に基づいてかなり柔軟に設定できます。一貫性のある確率を適用する方法から複数のサンプラーを扱う合成ルール、非確率的なロジックに基づくサンプリングなどを設定できます。

Datadog の場合、[ヘッドベースサンプリング](https://docs.datadoghq.com/ja/tracing/trace_pipeline/ingestion_mechanisms/#ヘッドベースサンプリング)により確率的なサンプリングと[エラーとレアトレース](https://docs.datadoghq.com/ja/tracing/trace_pipeline/ingestion_mechanisms/#エラーとレアトレース)による追加サンプリングや条件に応じた強制サンプリングなどを柔軟に設定できます。

### テールベースサンプリング
テールベースサンプリングは、スパンの生成後の転送時または保管時に、確率的または条件に応じてサンプリングする手法です。

ヘッドベースサンプリングと比較して、単一のスパンでサンプリングを決定する必要がなく、完全なトレースを確認した上でサンプリングを決定できることが大きなメリットです。ヘッドベースよりもサンプリング条件を細かく設定できるため取得したいトレースを確実に記録することができます。

OpenTelemetry の場合、OpenTelemetry Collector Processor でサンプリング条件を記載し、スパンの生成後の転送時に転送するスパンをサンプリングできます。

https://opentelemetry.io/blog/2022/tail-sampling/

Datadog の場合、バックエンドへのスパン取り込み後に [Ingestion Control](https://docs.datadoghq.com/ja/tracing/trace_pipeline/ingestion_controls/) で保管するスパンやトレースを詳細な条件で制御できます。

## おわりに
ログと同様にデータ量が膨大となるトレースは、その特性に合わせてサンプリングを行うことでコスト効率高く監視に活かすことができます。特に、記録するスパンや保管するスパンの条件をきちんと設定に反映しなければ、一部のスパンが欠けたトレースとなってしまうことも懸念されます。

従来の監視とは異なり、トレースはその記録方法から可視化の方法まで非常に分析・調査に有効な情報を記録します。トレースによってオブザーバビリティを向上し、正しく恩恵を受けるためにも、トレースをきちんとサンプリングして使いこなしていきましょう🐶

### 参考文献
 - **CNCF Tag Observability** 『[Observability Whitepaper](https://github.com/cncf/tag-observability/blob/main/whitepaper.md)』
 - **OpenTelemetry**『[OpenTelemetry - Traces](https://opentelemetry.io/docs/specs/otel/trace/)』
 - **Jaegar**『[Terminology - Trace](https://www.jaegertracing.io/docs/2.1/terminology/#trace)』
 - **Datadog**『[APM Terms and Concepts](https://docs.datadoghq.com/tracing/glossary/)』