相関IDの伝播を検証する
目標
W3Cのtraceparentを手で作って、3段のサービスチェーンに伝播し、ログをトレースIDで結合して、リクエスト1つの経路を復元します。
なぜ重要なのか
分散トレーシングを「3つ目のシグナルだから必要」と説明すると、導入に失敗します。正確にどんな質問に答えるのかを知っておく必要があります。10個のサービスのp99がすべて正常なのに、ユーザーの画面は2秒かかる状況では、メトリクスは原理的に無力です。集計値なので、個別のリクエストの経路を復元できないからです。1つのリクエストで、4msのクエリが340回実行されるN+1問題も、メトリクスには絶対に見えません。個別のクエリが速いからです。このラボでは、SDKなしで、ヘッダーの3つの断片だけでその経路を復元してみることで、後でOpenTelemetryを組み込むときに、何が実際に起きているのかを知った上で組み込めるようにします。
ステップ
/opt/app/chain.pyで、ゲートウェイ(8120)、注文(8121)、在庫(8122)の3つのサービスを起動してください。GET http://127.0.0.1:8120/orderが200を返します。/root/trace/gen.pyでtraceparentを作成して、/root/trace/tp.txtに1行で保存してください。00-<32hex>-<16hex>-01の形式でなければなりません。- そのヘッダーでゲートウェイを呼び出してください。3つのサービスがそれぞれ
/root/trace/svc-<이름>.logにtrace_id=<값>を残し(プレースホルダーは名前と値です)、3つの値がすべて同じでなければなりません。 - 各ログに、
span_id=<16hex>とparent_span_id=<16hex>も残してください。3つのサービスのspan_idは、互いに異なっていなければなりません。 /root/trace/join.shで、3つのログから同じtrace_idの行だけを取り出して、/root/trace/joined.logに時刻順に3行残してください。/opt/app/brokenchain.shを実行すると、8123/8124/8125に2つ目のチェーンが起動し、そのうち1つのサービスがヘッダーを捨てます。各サービスは、/root/trace/broken-<이름>.logにsvc=<이름> in_trace=<값> out_trace=<값>を残します(プレースホルダーは名前と値です)。入ってきたトレースIDと出ていったトレースIDが異なるサービスを見つけて、その名前を/root/trace/broken.txtに1行で書いてください。/root/trace/selftime.txtに、slowest=<서비스명> total_ms=<정수>とself_ms=<정수>の2行を書いてください(プレースホルダーはサービス名と整数です)。selfは、全体から子のスパンを引いた値です。
参考
- traceparentの形式:
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 - トレースIDはリクエスト全体で同じで、スパンIDはホップごとに変わります。
- 伝播が途切れる4か所: 独自のHTTPクライアント、スレッドプールへの受け渡し、メッセージキュー、ヘッダーを消すプロキシ。
- よくあるミス: トレースIDを大文字の16進数にすることです。仕様は小文字です。
3段のチェーンサービスを起動する
/opt/app/chain.pyで、ゲートウェイ(8120)、注文(8121)、在庫(8122)の3つのサービスを起動してください。GET http://127.0.0.1:8120/orderが200を返します。
/opt/app/chain.pyは、引数として受け取ったポートで起動し、次のホップのアドレスを環境変数で受け取ります。ゲートウェイ、注文、在庫の順に、3つを起動してください。
traceparentヘッダーを作る
/root/trace/gen.pyでtraceparentを作成して、/root/trace/tp.txtに1行で保存してください。00-<32hex>-<16hex>-01の形式でなければなりません。
バージョン2桁、トレースID32桁、スパンID16桁、フラグ2桁を、ハイフンでつなぎます。すべて小文字の16進数でなければなりません。
末端まで同じトレースIDを渡す
そのヘッダーでゲートウェイを呼び出してください。3つのサービスがそれぞれ/root/trace/svc-<이름>.logにtrace_id=<값>を残し(プレースホルダーは名前と値です)、3つの値がすべて同じでなければなりません。
各サービスが、受け取ったヘッダーからトレースIDだけをそのまま渡し、自分のログに残すようにしてください。
ホップごとにスパンIDを変える
各ログに、span_id=<16hex>とparent_span_id=<16hex>も残してください。3つのサービスのspan_idは、互いに異なっていなければなりません。
親スパンIDの位置には、自分のスパンIDを入れて送ります。3つのログのスパンIDがすべて異なっていれば正常です。
3つのログをトレースIDで結合する
/root/trace/join.shで、3つのログから同じtrace_idの行だけを取り出して、/root/trace/joined.logに時刻順に3行残してください。
サービスごとのログファイルを、トレースIDでふるい分けて、時刻順につなげます。結合の結果が、ちょうど3行でなければなりません。
伝播が途切れたサービスを見つける
/opt/app/brokenchain.shを実行すると、8123/8124/8125に2つ目のチェーンが起動し、そのうち1つのサービスがヘッダーを捨てます。各サービスは、/root/trace/broken-<이름>.logにsvc=<이름> in_trace=<값> out_trace=<값>を残します(プレースホルダーは名前と値です)。入ってきたトレースIDと出ていったトレースIDが異なるサービスを見つけて、その名前を/root/trace/broken.txtに1行で書いてください。
わざとヘッダーを捨てるサービスが1つあります。トレースIDが変わる地点を見つければ済みます。
自己時間を計算する
/root/trace/selftime.txtに、slowest=<서비스명> total_ms=<정수>とself_ms=<정수>の2行を書いてください(プレースホルダーはサービス名と整数です)。selfは、全体から子のスパンを引いた値です。
全体の継続時間から、子スパンの時間を引きます。最も遅い区間と、自己時間が大きい場所は、異なることがあります。