Deep Dive
Distributed Tracing
Observability Conference
田中 孝佳 @tanaka_733
資料は公開済です(セッション概要にリンクあります)
質問はカンファレンスのQ&AあるいはTwitterまで
登壇者紹介
田中 孝佳 (@tanaka_733)
New Relic K.K. Lead Technical Support Engineer
好きな言語はC#。C# Tokyoコミュニティの運営メンバー
OpenTelemetry .NETハンズオンなどを開催
Microsoft MVP for Azure, Development Technologies
Microsoft Certified Cloud Solution Architect Expert
Certified Kubernetes Administrator/Application Developer(CKA/CKAD)
本日のゴール
• オブザーバビリティにおけるトレースの重要性
• 分散トレースでなければわからないことを知る
• 分散トレースの構造の把握
• なぜつながるかを理解し、つながらない問題に対応できる
• 多数のトレースから注目すべきトレースを選ぶことの重要性
• 分散トレースのオーバーヘッドを理解し、
適切なサンプリング方法を設計できる
今日話さないこと
• メトリクス、ログとの連携
• 分散ツールの各計装ツールの固有の機能
• 個別のツールや言語における分散トレースの詳細
OpenTelemetryやW3C Trace Contextといった
オープンなプロジェクトを中心に
多くのツールで共通している概念をお話します
目次
• オブザーバビリティと分散トレース
• 分散トレースの概念と整理
• (分散)トレースとはなにか
• トレースの概念と用語を整理する
• 分散トレースをつなげる仕組み=伝搬
• 分散トレースをつなげる課題
• W3C Trace Context
• 多数のトレースから注目すべきものを見つける
=サンプリング
• グルーピングとサンプリング
• ヘッドベースサンプリングとテールベースサンプリング
オブザーバビリティと
分散トレース
なぜ監視するのか
マイクローサビスを採用ときに考慮すべき3つの能力
Fowler, Martin. 2014. Microservice Prerequisites. MartinFowler.com.
August 28, 2014.
https://martinfowler.com/bliki/MicroservicePrerequisites.html
HWの迅速な
プロビジョニング
SWの迅速な
デプロイ
重大な問題を迅速に
検出する監視
オブザーバビリティとは
問題
問題
問題
根本原因
オブザーバビリティーの3本柱
• サービス全体の傾向を
分析
• 数値化したテレメトリー
データを集約する
• 詳細なデバッグ情報を分
析
• プロセスから出力した
テキスト情報
メトリクス ログ
• サービスのボトルネック
を分析する
• リクエストの通過した
パスと構造を把握
トレース
(特に分散トレース)
分散トレースが生まれた背景
原因と結果が離れる ひとつひとつの要素は
壊れやすい
(単体のSLAは低い)
何百、何千の
ホスト(コンテナ)
分散トレースが必要な理由
「インシデントが発生している最中(一刻を争う時)に
根本原因を発見するために必要です。」
メトリクスでは
全体の傾向がわかっても
少数の異常な振る舞いが
埋もれがち
ログで詳細はわかるものの、
多数の要素のどのログを
見ればいいのかわからない
分散トレースが目指すもの
• システム内を流れるリクエストをテレメトリーデータで取得し、
分散システムのプロファイリングとモニタリングを可能に
• 少数の異常な振る舞いを検知可能に
• アプリケーションのパフォーマンス問題の
検出と解決にかかる時間を短縮可能に
• 多くの言語/フレームワーク/ランタイムで適用可能に
(今日はふれない内容)
分散トレース
の概念と構造
トレースの構造
Span A
Span B
Span C Span D
Span E
Span P
サービスA サービスB
root Span
(必ず1つだけ存在)
AのChild
Span
Caller Span
(呼び出しスパン)
Callee Span
(呼び出されたス
パン)
トレース内の作業の単位をスパンとし、
スパンのDAG(有向非巡回グラフ)として表現
スパンの属性
スパンに必要なデータは属性としてもたせる
• TraceID: 所属するトレースを一意に識別
• SpanID: 自身のスパンをトレース内で一意に識別
• ParentID: 自分の親スパンへの参照
• Name: スパンを表現する名前
• Start/End Time:
作業の開始・終了時刻から経過時間を算出
• Tags: キー値のペアで表現される追加の情報
• Events: トランザクション内での出来事を表現
トレースの表現方法
• スパンの親子関係に着目
• ボトルネック(経過時間)に着目
• サービスの依存関係に着目
スパンの親子関係に着目した表現方法
DAG
Span A
Span B
Span C Span D
Span E
Span P
サービスA サービスB
ボトルネックに着目した表現方法
time
Span A
Span B
C Span D
Span E
Span P
ボトルネック(どこで経過時間がかかっているか)を見つけるためには、
横軸を実時間にしたこのような表現が使われることが多い。
上の図では、SpanP、つぎにSpanDがボトルネックだとわかる
サービスの依存関係に着目した表現方法
Client
Notification
Purchase
DB
API
User
DB Ext
Client
API
User
Purchase
DB
Notifi
cation
Ext
分散システムにおいては、トレースからどのように呼び出されたか
(システムの依存関係)を見つけることもできる。
トレースの活用
• 有用なトレースを見つける è 最後の章へ
• 属性でクエリする
• 経過時間や数値型の属性をメトリクス化し、異常値を見つける
• ボトルネックを見つける
• エラーや例外状態のスパン
• 経過時間などの数値が異常値なスパン
• 正しく計測できているか確認すべきケース
• calleeとcallerの時間がずれているスパン
• 断片化されたスパン
エラーや例外状態のスパン
• アプリケーション例外がスローされた(予期せぬ例外)
• エラー状態とマークされたスパン(予期された例外)
• 応答コードがエラーのスパン
• HTTP呼び出しで4xxや5xxステータスレスポンスだった
• DB呼び出しでエラーが起きた
Span A
Span B
C DB エラー
status code=502エラー
アプリケーション例外
呼び出し側と呼び出された側の時間ずれ
caller span
callee span
ネットワーク、キュー
ロードバランサーなど
さまざまな要素での遅延
caller
callee
サーバー時刻のずれ
非同期処理
caller
callee
サーバー時刻のずれ
断片化されたスパン
Span A
子スパンが見えない
(大きな1つのスパン
しか見えない)
Span A
サービスY呼出 Span
サービスYのSpan
サービスZのSpan
呼び出されたスパンがない
つながっていないスパン
(Orphaned Span)
がある
Span
親スパンが見えない
断片化されたスパンへの対処(一例)
• みたいトレースがどのトレースでも見えない
• 計測コードが正しく実装されているか
• 同じトレースでも見えるときと見えないときがある
• サンプリングの問題 è 最後の章へ
• サービスを超えたトレースがつながらない
• 呼び出したトレースが独立している è 次の章へ
• 呼び出したトレースがみえない è 計測されている?
• その他考慮すべきこと
• スパンデータが到着していない
• 時刻のずれ
• バックエンドツール側の制約(UI上の制約など)
トレース計測のプラクティス「名前」
• 名前は集約可能
• POST /api/v1/users/12345
• ○ POST /api/v1/users/{id}
id=12345はタグとして記録
• 名前はリソースではなく、アクションを表すべき
リソースの種類はタグとして記録
• ReadBooksFromFile
• ○ ReadBooksを名前
storage=Fileをタグとして記録
トレース計測のプラクティス「タグ」
• カーディナリティの高いデータは名前ではなく、
タグとして使用する
• List?color=blue
• ○ Listが名前、color=blueはタグ
• 複数のシステムで共通化する
• bookidなのかbookIdなのかbook_idなのか統一
• わかりやすい名前
• lengthよりもlength_mm
• スパンが生成されたインフラの情報をタグに追加する
• サービスの名前、バージョン、
ホスト、コンテナ、ランタイム、地域・リージョンなど
トレース計測のプラクティス「スパン」
• ログよりも子スパンやタグ
• スパンでの処理がエラー状態であるならば
スパンの状態もエラーとする
• 回復不能なエラーであってもできる限りスパンを停止させる
• スパンは意味のある作業の単位で作成する
10:00:00 処理X開始 color=blue
10:01:23 処理X完了
スパン
Span X
(color=blue)
分散トレースをつなげる仕組み
=伝搬
サービス境界と分散トレース
• 呼び出した側と呼び出された側の対応づけが必要
• HTTP呼び出しのケースが多い
• trace idと呼び出した側のspan idの引き渡し
Span E
trace id:1234
span id: abcd
Span P
trace id=1234
parent span id=abcd
と設定しないといけない
ベンダー固有の実装と課題
• テキスト形式でフォーマットしたデータを
HTTPヘッダー経由でやり取り
• ヘッダー名やフォーマットが固有
Span E
trace id:1234
span id: abcd
Span P
vendoer_y:
{trace_id:1234,
parent_id:abcd}
異なるツール間でもトレースをつなげたい
Span Span P Span T
vendor_x:
xxx_format
vendor_y:
yyy_format
vendor Yの計測ツールは
vendor_xフォーマットを認識できないため
Span Pが親となる新規のトレースとして記録される
W3C Trace Context
分散トレースのためのHTTPヘッダーのフォーマットの標準規格
https://www.w3.org/TR/trace-context/
traceparent: トレースIDと呼び出しスパンIDを識別
tracestate: ベンダー固有の情報
W3C Trace Contextの詳細
traceparent:
バージョン(2バイト)-トレースID(16バイト)-スパンID(8バイト)-ト
レースフラグ(8ビット)
例) 00-07b4bf1339212a6e634ede07e21e8a72-
ded04c84c8082456-01
tracestate:
トレースを記録するベンダーツールごとに利用
例: New Relicの場合
アカウント、親スパンの種類、アプリケーションID、
スパンID、トレースID、
サンプリング有無、優先度など
W3C Trace Contextでの
トラブルシューティング
• 呼び出し側がtraceparentヘッダーを送出しているか?
• 呼び出された側が同じtraceparentを受け取っているか?
• プロキシやLBなど中間要素が除去・改変していないか確認
• 両者のスパンが同じTraceIdを持つことを確認
• 異なる場合は呼び出された側のトレースの計装を確認
(traceparentのTraceIdを適用する方法)
W3C Trace Contextの課題
• job queue/pubsubなどHTTP以外での依存関係
• HTTPヘッダーのようなデータをやり取りできる標準機能がない
• 技術的にはtraceparentをやり取りできれば繋げられる
• 分散トレースの定義上、1つに表現しづらいパターン
• 例えばfork-joinパターン
• トレースやスパンの属性を使って、
関連する複数のトレースをまとめられるようにする
traceid=123, jobid=abc
traceid=456, jobid=abc
traceid=789, ex_jobid=abc
多数のトレースから見るべき
トレースに注目する方法
藁の山から針を見つけるために
• 山の量をへらす è サンプリング
• 山を束に分けて見つけやすくする è グルーピング
多数のトレースの表現方法
• 詳細な実装はツール依存ではあるが、その概念は共通になりつ
つあるので整理したい
• 計測ツールのどこで行うかがポイント
アプリ
計測
ツール
アプリ
計測
ツール
コレクター
バックエンド
(トレースの保管・
可視化)
グルーピング
• トレースやスパンの属性ごとに分類する
• トレースの名前ごと
• DBの操作ごと
• 分類した中で異常値を見つける
• エラー状態のスパンを含むもの
• 経過時間が平均から外れたもの
必要な属性を計測ツールやコレクターで付加し
バックエンドの可視化機能として提供することが多い
サンプリング
• 多数あるものから注目したいものだけを選ぶ
• 事前にメトリクスで集約することで全体の傾向はつかめる
• 異常な、問題を含んでいるトレースを選択したい
異常値
エラー
トレースの収集方法とサンプリング
アプリ
計測
ツール
コレクター
バックエンド
(トレースの保管・
可視化)
サービスごとの
サンプリング
サービス全体での
サンプリング
保管時の制約
UI表示上の制約
ヘッドベースサンプリング
あるいはアップフロントサンプリング
トレースの開始時点でサンプリングするかどうか決める
• 親スパンから先のすべてのスパンに
サンプリングされたことを伝える必要がある
• 事前に決定するため、経過時間が長かったりエラーが起きたりした
トレースを見逃す可能性がある
テールベースサンプリング
あるはレスポンスベースサンプリング
サービスX
サービスY
サービスZ
トレースが完了してから、サンプリングするかどうか決める
テールベースサンプリングが
注目される理由
• トレースの全体像を見て判断できるため、
少数のエラースパンや経過時間の長いスパンを
見逃さず選択できる
• エラーのあるスパンは100%、
その他のスパンは10%
のような選択ロジックも可能
テールベースサンプリング
実装する仕組みと課題
• 自社サービス全部のトレースを処理する必要性
• 完了していないすべてのスパンをバッファし、
サンプリング判定する必要性
• ネットワーク転送量、コレクターの可用性、
バックエンドツールの保存コストなどの運用が必須
• 最近ではマネージドなコレクターを提供するSaaSも
アプリ
計測
ツール
コレクター
アプリ
計測
ツール
確率的サンプリング
適用型サンプリング(adaptive sampling)など近い概念も
サービスX
サービスY
サービスZ
OpenTelemetryではtracestateを使って確率的サンプリングを行う
仕様がExperimentalで検討中
https://opentelemetry.io/docs/reference/specification/
trace/tracestate-probability-sampling/
親スパンがサンプルされたかと
サンプリングの確率を伝搬させ、
子スパンごとに再度計算した確率で
サンプリングを行う
まとめ
まとめ
• 分散トレースによりサービス全体のボトルネックを分析
• 分散トレースは作業の単位であるスパンのDAGで表現
• ボトルネックを見つけやすくするよう
スパンの名前やタグづけを考える
• W3C Trace Contextにより計測ツールが異なっても
分散トレースがつながるようになった
• 少数のエラーや異常なスパンを見つけるには
テールベースサンプリングという手法がある

deep dive distributed tracing