本記事はOpenTelemetry Advent Calendar 2023の16日目の記事になります。
昨日は@munisystemさんのOpen Agent Management Protocol (OpAMP) についてでした。
本記事ではW3C Trace Contextの内容を要約しています。
また、本記事を読む前にOpenTelemetry Advent Calendar 2023 3日目の@sumirenさんによるOpenTelemetry 分散トレーシングのシステムアーキテクチャを読んでいただくと理解が深まると思います。
OpenTelemetryとの関係性
OpenTelemetryのContext Propagationは複数のフォーマットをサポートしていますが、デフォルトで使用されるフォーマットがW3C Trace Contextになります。つまり標準ではW3C Trace Contextの形式でHTTPヘッダーを挿入し、トレース情報を伝播していきます。
W3C Trace Contextとは
W3C Trace Contextは、分散システムにおけるトレース情報の伝播を標準化するための仕様です。HTTPヘッダーと値の形式を定義し、それによって分散トレーシングを可能にします。具体的には、各サービス間でコンテキスト情報を送信し、変更する方法を標準化しています。その名の通り、World Wide Web Consortium (W3C)によって標準されています。
このコンテキスト情報は、分散システム内の個々のリクエストを一意に識別し、プロバイダ固有のコンテキスト情報を追加し、伝播する手段を定義します。これにより、異なるトレーシングベンダーによって収集されたトレースを相互に関連付けることが可能になります。
トレースコンテキストのHTTPヘッダーフォーマット
分散トレースにおけるコンテキストとして、traceparent
とtracestate
の2つを定義しています。
traceparentは、そのトレースにおけるリクエストの位置を移植可能な固定長フォーマットで記述します。その設計は高速な解析に重点を置いています。すべてのトレースツールは、 tracestate のベンダ固有の情報のみに依存する場合でも、 traceparent を適切に設定しなければなりません。
tracestateは、名前と値のペアのセットで表されるベンダー固有のデータで traceparent を拡張します。tracestate に情報を格納することはオプションです。
最低限、traceparent
とtracestate
ヘッダーを伝搬し、トレースが壊れないことを保証しなければなりません。この動作はトレースの転送とも呼ばれます。
さらに、トレースはtraceparent
ヘッダーとtracestate
ヘッダーの関連部分を修正することで、トレースに参加することもできます。これはトレースへの参加とも呼ばれます。
トレースツールは、監視しているコンポーネントへの個々のリクエストごとに、この動作を変更することができます。
ヘッダー間の関係性
traceparent
ヘッダーは、トレースシステムの受信リクエストを、すべてのベンダが理解できる共通のフォーマットで表します。以下は traceparent
ヘッダーの例です。
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate
ヘッダーは、ベンダ固有の形式である可能性のある親を含みます:
tracestate: congo=t61rcWkgMzE
例えば、あるシステムのクライアントとサーバーが異なるトレーシング・ベンダーを使用しているとします: CongoとRojoです。Congo システムでトレースされたクライアントは、送信HTTP リクエストに以下のヘッダーを追加します。
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: congo=t61rcWkgMzE
Rojoトレースシステムでトレースされた受信サーバーは、受信したtracestateを引き継ぎ、左側に新しいエントリを追加します。
traceparent: 00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01
tracestate: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE
Rojoのシステムはtracestate
のエントリにtraceparent
の値を再利用しています。これは、一般的なトレースシステムであることを意味します(独自の情報は渡されません)。そうでない場合、tracestate
のエントリは不透明で、ベンダ固有である可能性があります。
次の受信サーバーがCongoを使用する場合、Rojoからのtracestate
を引き継ぎ、前のエントリの左に親の新しいエントリを追加します。
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01
tracestate: congo=ucfJifl5GOE,rojo=00f067aa0ba902b7
注: ucfJifl5GOE
は、Base64 エンコードされた親 ID b9c7c989f97918e1
です。
Congoがそのtraceparent
エントリーを書いたとき、それがエンコードされていないことに注意する必要があります。しかしtracestate
の値はエンコードされており、traceparent
とは異なります。これは問題ありません。
最後に、tracestate
はRojoのエントリを、右にプッシュされている以外は、そのまま保持していることがわかります。一番左の位置は、次のサーバーにどのトレースシステムがtraceparent
に対応するかを知らせます。この場合、Congoがtraceparent
を書いたので、そのtracestate
のエントリは一番左になるはずです。
Traceparent ヘッダー
traceparent
HTTPヘッダーフィールドはトレースシステムで受信リクエストを識別し、以下の4つのフィールドから構成されています。
- version
- trace-id
- parent-id
- trace-flags
Tracestateヘッダー
tracestate
HTTP ヘッダーの主な目的は、異なる分散トレースシステム間で追加のベンダ固有のトレース識別情報を提供することであり、traceparent
フィールドのコンパニオンヘッダーです。また、複数の分散トレースグラフにおけるリクエストの位置についての情報も伝えます。
トレースコンテキストの処理モデル
この処理モデルは、トレースコンテキストヘッダーを修正して転送するベンダーの動作を記述します。このモデルがどのように動作するかは、traceparent
ヘッダーを受信するかどうかに依存します。
トレースペアレントの受信なし
traceparentヘッダーを受け取らない場合:
- ベンダは受信リクエストに
traceparent
ヘッダーとtracestate
ヘッダーがないかチェックします。 -
traceparent
ヘッダーが受け取られないので、ベンダーは現在のリクエストを表す新しいtrace-id
とparent-id
を作成します。 -
traceparent
ヘッダーを伴わずにtracestate
ヘッダーを受け取る場合、それは無効なので破棄されなければならない。 - ベンダーは新しい
tracestate
ヘッダーを生成し、新しいkey/valueペアを追加すべきである。 - ベンダーは発信リクエストに
traceparent
ヘッダーとtracestate
ヘッダーを設定します。
トレースペアレントの受信
traceparent
ヘッダーを受信した場合:
-
traceparent
ヘッダーを受け取った場合: ベンダーは受信リクエストにtraceparent
ヘッダーとtracestate
ヘッダーがあるかどうかチェックします。 -
traceparent
ヘッダーが存在するので、ベンダーはtraceparent
ヘッダーの バージョンの解析を試みます。- バージョンが解析できない場合、ベンダは新しい
traceparent
ヘッダーを作成し、tracestate
を削除します。 - バージョン番号がトレーサがサポートするバージョンより高い場合、ベンダーはこの仕様で定義されたフォーマット (
00
) を使用してtrace-id
とparent-id
を解析します。ベンダーは、この仕様のこのバージョンでサポートされているtrace-flags
値のみを解析し、その他の値はすべて無視します。解析に失敗した場合、ベンダーは新しいtraceparent
ヘッダーを作成し、tracestate
を削除します。ベンダーは発信リクエストに対して、すべての解析されていない / 未知のtrace-flags
を0に設定します。 - ベンダーがバージョン番号をサポートしている場合、
trace-id
とparent-id
を検証します。trace-id
、parent-id
、trace-flags
のいずれかが無効な場合、ベンダーは新しいtraceparent
ヘッダーを作成し、tracestate
を削除します。
- バージョンが解析できない場合、ベンダは新しい
- ベンダーは
tracestate
ヘッダーを検証してもよい。tracestate
ヘッダーを解析できない場合、ベンダーはヘッダー全体を破棄してもよい。無効なtracestate
エントリも破棄してもよい。 - 各送信リクエストに対して、ベンダーは以下の手順を実行します:
- ベンダーは
traceparent
ヘッダーを修正しなければならない:-
parent-id
の更新:parent-id
プロパティの値を、現在の操作のIDを表す値に設定しなければならない。 -
sampled
の更新:sampled
の値は、呼び出し元の記録動作を反映します。trace-flags
のsampled
フラグの値は、トレースデータが記録される可能性が高い場合は1
に、そうでない場合は0
に設定してもよい。このフラグを設定することは、トレースが記録されることを保証するものではありませんが、エンドツーエンドで記録されるトレースの可能性を高めます。
-
- ベンダーは tracestate ヘッダーを修正してもよい:
- キーバリューの更新: キーの値を更新する: 任意のキーの値を更新することができます。変更されたキーはリストの先頭(左)に移動しなければならない。
- 新しいキーとバリューのペアの追加: 新しいキーと値のペアは、リストの先頭(左)に追加されなければなりません。
- キーと値のペアの削除: どのkey/valueペアも削除してもよい。ベンダーは、自分で生成していないキーを削除すべきではない。キーと値のペアを削除すると、他のシステムとの相関が壊れてしまうかもしれません。
- ベンダーは発信リクエストに
traceparent
ヘッダーとtracestate
ヘッダーを設定します。
- ベンダーは
まとめ
さらに細かい詳細はぜひW3C Trace Contextをご確認ください。また、W3C Editor's DraftとしてTrace Context Level 3が議論されています。気になる方はこちらもチェックしてみてください。