分散トレーシング: リクエスト フローを理解する
Il 分散トレーシング そして完全なパスをたどることができるテクニック 分散システムを介したリクエストのエントリ ポイントから最終応答まで。 1 つのユーザー リクエストが 10、20、あるいはそれ以上のユーザー リクエストを横断できるマイクロサービス アーキテクチャ サービスでは、分散トレースがフローのエンドツーエンドのビューを取得する唯一の方法です ボトルネック、エラー、隠れた依存関係を特定します。
各リクエストは トレース (トラック)、一連の要素で構成されます。 スパン ツリー構造で相互に接続されています。各スパンは次のことを表します 作業単位: HTTP 呼び出し、データベース クエリ、キューにポストされたメッセージ。 スパンを組み合わせると、処理中に何が起こったかの完全なストーリーがわかります。 リクエストの。
この記事で学べること
- OpenTelemetry の Trace と Span の構造
- 伝播用の W3C Trace Context プロトコル
- 親子関係とスパン間のリンク
- SpanKind: クライアント、サーバー、プロデューサー、コンシューマー、内部
- スパン属性、イベント、ステータス
- 表示パターン:ウォーターフォールとサービスマップ
トレースの構造
Una トレース およびパスを表すスパンの有向非巡回グラフ (DAG)
リクエストの。各トレースには一意の識別子 (trace_id) 128 ビット
これは、関連するすべてのサービスを通じて伝播されます。初期スパンは次のように呼ばれます。
ルートスパン 開始から終了までの操作全体を表します。
Trace ID: 4bf92f3577b34da6a3ce929d0e0e4736
[Root Span] API Gateway - POST /api/orders (250ms)
|
+-- [Child Span] Order Service - validate-order (15ms)
|
+-- [Child Span] Order Service - check-inventory (45ms)
| |
| +-- [Child Span] Inventory Service - GET /stock (40ms)
| |
| +-- [Child Span] Database - SELECT stock (8ms)
|
+-- [Child Span] Order Service - process-payment (120ms)
| |
| +-- [Child Span] Payment Service - charge (115ms)
| |
| +-- [Child Span] External API - Stripe charge (100ms)
|
+-- [Child Span] Order Service - send-confirmation (30ms)
|
+-- [Child Span] Notification Service - send-email (25ms)
スパンの構造
Uno スパン トレース内の単一の操作を表します。含まれています 何が起こったのか、どれくらい時間がかかったのかを理解するために必要なすべての情報 エラーが発生したかどうか。各スパンには明確に定義された構造があります。
from opentelemetry import trace
from opentelemetry.trace import StatusCode, SpanKind
tracer = trace.get_tracer("order-service", "1.0.0")
def process_payment(order_id, amount, currency):
# Creare uno span con tutti i componenti
with tracer.start_as_current_span(
name="process-payment",
kind=SpanKind.CLIENT, # Tipo di span
attributes={ # Attributi iniziali
"order.id": order_id,
"payment.amount": amount,
"payment.currency": currency,
"payment.provider": "stripe"
}
) as span:
try:
# Aggiungere un evento (timestamp automatico)
span.add_event("payment.validation.started", {
"validation.rules": "amount,currency,card"
})
validate_payment(amount, currency)
span.add_event("payment.validation.completed")
# Chiamata al provider di pagamento
result = stripe_client.charge(amount, currency)
# Aggiungere attributi dopo l'esecuzione
span.set_attribute("payment.transaction_id", result.tx_id)
span.set_attribute("payment.status", "success")
# Impostare lo status
span.set_status(StatusCode.OK)
return result
except PaymentDeclinedException as e:
# Registrare l'eccezione come evento
span.record_exception(e)
span.set_status(StatusCode.ERROR, "Payment declined")
span.set_attribute("payment.decline_reason", str(e))
raise
except TimeoutError as e:
span.record_exception(e)
span.set_status(StatusCode.ERROR, "Payment gateway timeout")
span.add_event("payment.retry.scheduled", {
"retry.attempt": 1,
"retry.delay_ms": 1000
})
raise
スパンのコンポーネント
| 成分 | 説明 | Esempio |
|---|---|---|
| トレースID | 一意のトレース ID (128 ビット) | 4bf92f3577b34da6a3ce929d0e0e4736 |
| スパンID | 一意のスパン ID (64 ビット) | 00f067aa0ba902b7 |
| 親スパン ID | 親スパン ID (ルートの場合は空白) | a1b2c3d4e5f6a7b8 |
| 名前 | 操作のわかりやすい名前 | process-payment |
| 親切 | スパンのタイプ (CLIENT、SERVER など) | SpanKind.CLIENT |
| 開始時刻 | 開始タイムスタンプ | 2026-02-17T10:30:00.000Z |
| 終了時刻 | 終了タイムスタンプ | 2026-02-17T10:30:00.120Z |
| 属性 | 説明的なキーと値のペア | payment.amount=99.99 |
| イベント | タイムスタンプ付きの時間厳守のログ | payment.validation.completed |
| 状態 | OK、エラー、または設定解除 | StatusCode.OK |
W3C トレース コンテキスト: 伝播標準
Il W3C トレース コンテキスト トレースのコンテキストを定義する標準 サービス境界を越えて伝播されます。 2 つの HTTP ヘッダーを指定します。 サービス間のすべてのリクエストに以下が含まれます。
# Header W3C Trace Context
# traceparent: contiene trace_id, parent_span_id, trace_flags
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
| | | |
v v v v
version trace_id (32 hex) parent_span_id (16 hex) flags (sampled=01)
# tracestate: stato specifico del vendor (opzionale)
tracestate: congo=t61rcWkgMzE,rojo=00f067aa0ba902b7
サービスがヘッダー付きのリクエストを受信したとき traceparentを抽出します。
trace_id そして parent_span_id、同じ子スパンを使用して新しい子スパンを作成します
trace_id そして、更新されたコンテキストを後続の呼び出しに伝播します。この仕組み
リクエストのすべてのスパンが同じものを共有するようにします trace_id.
SpanKind: 操作の分類
Il スパンカインド リクエスト フローにおけるスパンの役割を分類します。これ システム トポロジを再構築する必要があるバックエンドの情報と基本 サービス間のレイテンシーを計算します。
from opentelemetry.trace import SpanKind
# SERVER: il servizio riceve una richiesta da un client remoto
with tracer.start_as_current_span("handle-request", kind=SpanKind.SERVER):
# Gestire la richiesta HTTP in arrivo
pass
# CLIENT: il servizio invia una richiesta a un servizio remoto
with tracer.start_as_current_span("call-payment-api", kind=SpanKind.CLIENT):
# Chiamata HTTP verso payment-service
pass
# PRODUCER: il servizio invia un messaggio a un broker
with tracer.start_as_current_span("publish-order-event", kind=SpanKind.PRODUCER):
# Pubblicazione su Kafka topic
pass
# CONSUMER: il servizio riceve un messaggio da un broker
with tracer.start_as_current_span("process-order-event", kind=SpanKind.CONSUMER):
# Consumo da Kafka topic
pass
# INTERNAL: operazione interna al servizio (default)
with tracer.start_as_current_span("validate-order", kind=SpanKind.INTERNAL):
# Logica interna di validazione
pass
SpanKind の選択ルール
- サーバ: サービスが同期リクエスト (HTTP、gRPC) の受信者である場合に使用します。
- クライアント: サービスが別のサービスに同期リクエストを送信するときに使用します。
- プロデューサー: サービスが非同期メッセージを生成する場合に使用します (Kafka、RabbitMQ、SQS)
- 消費者: サービスが非同期メッセージを使用する場合に使用します。
- 内部: ネットワーク境界を越えない内部操作に使用します。
スパンリンク: 異なるトラックを接続する
OTel は親子関係に加えて、 スパンリンク 接続する 異なるトラックに属するスパン。リンクは、操作が次のような非同期シナリオで行われる場合に役立ちます。 これは別の原因によって引き起こされますが、その直接の娘ではありません。たとえば、キュー内のメッセージ コンシューマ トレースが異なる場合でも、それを生成したスパンにリンクできます。
from opentelemetry import trace, context
# Scenario: batch processing di messaggi da una coda
# Ogni messaggio ha il suo trace context originale
def process_batch(messages):
# Creare link a tutti i messaggi del batch
links = []
for msg in messages:
# Estrarre il trace context dal messaggio
msg_context = extract_context(msg.headers)
span_context = trace.get_current_span(msg_context).get_span_context()
links.append(trace.Link(
context=span_context,
attributes={"messaging.message.id": msg.id}
))
# Creare uno span con link a tutti i messaggi originali
with tracer.start_as_current_span(
name="process-message-batch",
kind=SpanKind.CONSUMER,
links=links,
attributes={
"messaging.batch.message_count": len(messages)
}
) as span:
for msg in messages:
process_single_message(msg)
トラックの表示
デプロイされたトレースは通常、次の 2 つの補完的な方法で表示されます。
ウォーターフォール ビュー (ガント チャート)
ウォーターフォール ビューでは、スパンが時間順に表示され、関係がインデントされます。 親子。どこに時間が費やされたのか、どの時間に費やされたのかをすぐに特定できます。 操作は逐次的なものと並列的なものがあります。シングルのデバッグに最もよく使用されるビューです 遅いリクエスト。
サービスマップ(トポロジ)
サービス マップは、サービス間の依存関係を有向グラフとして表示します。各ノードが表すのは、 サービス、それぞれのアーチがコミュニケーションです。集計メトリクス (レイテンシー、エラー率、スループット) アーチに重ねられています。アーキテクチャ全体を理解するための理想的なビュー 重要なサービスや障害点を特定します。
分散トレースのベスト プラクティス
名前は URL ではなく操作にまたがります: アメリカ create-order、 ない
POST /api/v1/orders。カーディナリティの高い URL (ID を含む) では、集計の問題が発生します。
ビジネス関連の属性を追加する: order.id, user.tier,
payment.method トレースを技術ツールからビジネス分析ツールに変換します。
Record_Exception を使用して例外を記録する: タイプ、メッセージを自動的にキャプチャ
エラーをスパン イベントとしてスタックトレースします。
SpanKind を正しく使用する: バックエンドでネットワーク遅延を計算できるようにします。
(CLIENT スパンと対応する SERVER スパンの違い)。
結論と次のステップ
分散トレーシングはシステムの動作を理解するための基本的なツールです 配布されました。トレース コンテキスト伝播 (W3C)、属性を備えた構造化スパンの組み合わせ セマンティクスと視覚化ウォーターフォール/サービス マップは、以下に必要な可視性を提供します。 サービスの境界を越える複雑な問題を診断します。
SpanKind の正しい選択、意味のある属性の使用、およびイベント ログ記録 例外により、トラックが単純なタイムラインから強力な分析ツールに変換されます。 それぞれのリクエストの詳細を説明します。
次の記事では、自己計測を可能にするテクニック エージェントとライブラリを使用して、アプリケーション コードを変更せずに分散トレースを取得する Java、Python、Node.js の自動インストルメンテーション。







