コンテンツにスキップ

分散トレース@テレメトリー

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. 分散トレース

分散トレースとは

マイクロサービスから収集されたスパンのセットのこと。

スパンをトレースIDで紐付けることによって、1個のリクエストで発生したマイクロサービスを横断する処理を、一繋ぎに表現できるようになる。

distributed-trace


分散トレースの用途

▼ レスポンスタイムの最適化

分散トレースを収集すると、マイクロサービス間のレスポンスタイムを可視化できる。

例えば、性能テストでシステム全体の性能のデグレーションがあったとする。

分散トレースで特定のマイクロサービス間でレスポンスタイムを可視化できるため、いずれのマイクロサービス間の通信がボトルネックになっているかがわかる。

そのダウンストリーム側マイクロサービスのリクエストまたはアップストリーム側マイクロサービスのレスポンスに関して、性能に問題がないかを調査する必要がある。

distributed-trace_connection-time

▼ 悪意のあるリクエストの検出

分散トレースを収集すると、悪意のあるリクエストを検出できる。

例えば、特定のマイクロサービスへのリクエストが異常に多ければ、そのマイクロサービスに悪意のあるリクエストが送信されている可能性がある。


分散トレースの読み方

上から下に読むと、ダウンストリーム側マイクロサービス (上位スパン) がアップストリーム側マイクロサービス (下位スパン) を処理をコールしていることを確認できる。

下から上に読むと、アップストリーム側マイクロサービス (下位スパン) からダウンストリーム側マイクロサービス (上位スパン) に結果を返却していることを確認できる。

distributed-trace_reading


モノリシックアーキテクチャにおける分散トレース

モノリシックアーキテクチャなアプリケーションでは、システムが分散していないため、単なるトレースとなる。

*例*

(1)

a1:クライアントがリクエストを送信する。

(2)

a1:リクエストがロードバランサ-に到達する。

(3)

a1a2:ロードバランサ-で処理が実行される。

(4)

a2:ロードバランサ-がリクエストをアプリケーションにルーティングする。

(5)

a2:リクエストがアプリケーションに到達する。

(6)

a2a3:アプリケーションで処理が実行される。

(7)

a3:アプリケーションがレスポンスをクライアントに返信する。

monolith-trace


02. トレースコンテキスト

トレースコンテキストとは

各スパンに含まれる情報のこと。

  • 各種ID
  • マイクロサービスの属性情報


トレースコンテキスト作成の仕組み

ロードバランサー (例:Istio IngressGateway、AWS ALB) やAPI Gateway (例:AWS API Gateway) が最初にトレースコンテキストを作成する。

これらは、トレースコンテキストがIDが持っているかを検証する。

もしIDがなければ、スパンにIDを新しく割り当てる。

distributed-tracing

▼ IDの種類

トレースコンテキストには、以下のIDが含まれている。

ID 説明
トレースID リクエストIDである。全てのマイクロサービスで同じになる。
スパンID 各マイクロサービス固有の処理IDである。 全てのマイクロサービスで異なっている。
親スパンID クライアントのマイクロサービスの処理IDである。クライアントが同じマイクロサービス間で同じになる。

▼ トレースコンテキスト伝播 (分散トレースコンテキスト伝播)

マイクロサービスで、受信した通信のヘッダーから分散トレースのトレースコンテキストを取得し、アウトバウンド通信のヘッダーにトレースコンテキストを渡すような、実装が必要である。

分散トレースの監視バックエンド (例:OpenTelemetry、LightStep、Jaeger、Zipkin、Datadog、AWS X-Ray) ごとに、ヘッダーからトレースコンテキストを簡単に取り出せるパッケージを使用すると良い。

インバウンド通信がHTTPプロコトルでアウトバウンド通信が、gRPCによるHTTPリクエストである場合も、ヘッダー間での受け渡しが必要である。

▼ 異なる言語間での受け渡し

  • 異なる言語の各アプリで、計装パッケージによるTracerProviderのセットアップやスパンの作成は必要
  • 言語間で計装パッケージのトレースコンテキスト仕様は標準化されているため、言語が違ってもCarrierからトレースコンテキストの情報 (スパンID、トレースIDなど) を抽出したり注入したりできる


トレースコンテキスト仕様の種類

▼ 一覧

トレースコンテキストにはいくつかの仕様があり、仕様ごとにCarrierやデータ形式が異なる。

  • W3C Trace Context
  • W3C Baggage
  • B3 (Zipkin)
  • Jaeger
  • 独自仕様 (AWS X-Ray、Datadog、LightStepなど)

▼ W3C Trace Context

W3C Trace Context仕様のIDは以下の通りである。

項目
trace-id 32進数
parent-id 16進数
trace-flags 2進数

これらの値によってトレースコンテキストが決まる。

GET /foo-service HTTP/1.1
---
Host: example.com
# バージョン、トレースID、親スパンID、トレースフラグ、をリスト形式で運ぶ
traceparent: 00–0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331–01
# セッションID、特定のリクエストにのみ付与されたデータなどをリスト形式で運ぶ
tracestate: abc=00f067aa0ba902b7,xyz=99f067aa0ba902b7

▼ B3 (Zipkin)

B3仕様のIDは以下の通りである。

項目
trace-id 1632進数
span-id 16進数
parent-span-id 16進数
sampling-state サンプリング無効なら0、有効なら1

これらの値によってトレースコンテキストが決まる。

GET /foo-service HTTP/1.1
---
Host: example.com
# トレースID、スパンID、サンプリングステート、親スパンID、をエンコードして運
b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90

▼ X-Ray

X-Ray仕様のIDは以下の通りである。

項目
trace-id version (1) + タイムスタンプ (16進数) + ユニークID (16進数)
span-id
GET /foo-service HTTP/1.1
---
# <バージョン>-<ルートセグメントのタイプスタンプ>-<サブセグメントごとのユニークID>
trace_id: 1-58406520-a006649127e371903a2de979


ツールごとのCarrier

▼ Carrierとは

トレースコンテキストをアップストリーム側マイクロサービスに伝播させる処理を持つ。

伝播に使用する媒体 (例:HTTPヘッダー、メッセージボディ、gRPCメタデータなど) を『Carrier』という。

distributed-trace_propagated

▼ 標準ヘッダー

ヘッダー名 説明
X-REQUEST-ID トレースIDが割り当てられている。
GRPC-TRACE-BIN RPCによるリクエストにて、トレースIDが割り当てられている。

▼ zipkin系ヘッダー

Zipkinが使用するヘッダーを追加する。

ヘッダー名 説明 値の例
X-B3-SAMPLED 1
X-B3-SPANID スパンIDが割り当てられている。 a2fb4a1d1a96d312
X-B3-TRACEID トレースIDが割り当てられている。 463ac35c9f6413ad48485a3953bb6124
X-B3-PARENTSPANId 親のスパンIDが割り当てられている。ルートスパンの場合、このヘッダーは追加されない。 0020000000000001

▼ AWS X-Ray系ヘッダー

AWS X-Rayが使用するヘッダーを追加する。

ヘッダー名 説明 値の例
X-AMZN-TRACE-ID トレースIDが割り当てられている。トレースIDはALBで作られる。 1-5759e988-bd862e3fe1be46a994272793


03. スパン

スパンとは

マイクロサービスアーキテクチャの特定のサービスにて、1つのリクエストで発生したデータのセットのこと。

スパンには親子関係があり、最上位の親スパンを『ルートスパン』ともいう。

JSON型で定義されることが多い。

SaaSツールによってJSON型の構造が異なる。


スパン名

スパンが作成されたクラス (構造体) やメソッド (関数) が判別しやすいようにする。

例えば、ユーザー情報を取得するマイクロサービスのスパン名として、以下の候補がある。

区切り記号は、ドット (.) や スラッシュ(/) が良い。

スパン名 構成 良し悪し 補足
get <HTTPメソッド名> ×
get_account.42 <アプリのメソッド名>.<ID> ×
get_account <アプリのメソッド名> ⭕️ スパンの属性にアカウントIDを設定するとよい。
get_account.accountId <アプリのメソッド名>.<エンドポイント名> ⭕️


スパンの属性

領域 内容
バックエンド イベントの内容 トレースID、スパンID、親スパンID、処理の開始時間、処理の所要時間、エラーの有無、マイクロサービスの役割名、コールされたエンドポイントなど
ラベル マイクロサービス名など


スパンの粒度

スパンの適切な粒度は、マイクロサービスの粒度による。

マイクロサービスの粒度 スパンの粒度
境界づけられたコンテキスト マイクロサービスごと、関数ごとに
ルートエンティティ マイクロサービスごと


データポイント化

スパンが持つデータをデータポイントとして集計することにより、メトリクスのデータポイントを収集できる。


04. プロファイル

プロファイルとは

分散トレースのスパンにハードウェアリソース消費量の情報を加えたもの。