次の方法で共有


.NET 分散トレースの概念

分散トレースは、エンジニアがアプリケーション内の障害とパフォーマンスの問題 (特に複数のマシンまたはプロセスに分散される可能性がある問題) をローカライズするのに役立つ診断手法です。 分散トレースが役立つ一般的な情報については、「分散トレースの概要」 を参照してください。

トレースとアクティビティ

アプリケーションが新しい要求を受信するたびに、その要求をトレースに関連付けることができます。 .NET で記述されたアプリケーション コンポーネントでは、トレース内の作業単位は System.Diagnostics.Activity のインスタンスによって表され、トレース全体がこれらのアクティビティのツリーを形成し、多くの異なるプロセスにまたがる可能性があります。 新しい要求に対して作成された最初のアクティビティは、トレース ツリーのルートを形成し、要求を処理する全体的な期間と成功/失敗を追跡します。 必要に応じて、子アクティビティを作成して、個別に追跡できるさまざまなステップに作業を分割できます。 たとえば、Web サーバー内の特定の受信 HTTP 要求を追跡するアクティビティを考えると、要求を完了するために必要な各データベース クエリを追跡する子アクティビティを作成できます。 これにより、各クエリの期間と成功を個別に記録できます。 アクティビティは、OperationNameTagsと呼ばれる名前と値のペア、Eventsなど、作業単位ごとに他の情報を記録できます。 この名前は、実行されている作業の種類を識別し、タグは作業の説明パラメーターを記録でき、イベントはタイムスタンプ付き診断メッセージを記録するための単純なログ記録メカニズムです。

手記

分散トレース内の作業単位のもう 1 つの一般的な業界名は、"スパン" です。 .NET では、この概念に対して "Span" という名前が確立される前に、何年も前に "Activity" という用語が採用されていました。

活動 ID

分散トレース ツリー内のアクティビティ間の Parent-Child リレーションシップは、一意の ID を使用して確立されます。 .NET の分散トレースの実装では、2 つの ID スキームがサポートされています。W3C 標準 TraceContext(.NET 5 以降では既定値) と、下位互換性のために使用できる "階層型" と呼ばれる以前の .NET 規則です。 Activity.DefaultIdFormat は、使用する ID スキームを制御します。 W3C TraceContext 標準では、すべてのトレースにグローバルに一意の 16 バイトのトレース ID (Activity.TraceId) が割り当てられ、トレース内のすべてのアクティビティに一意の 8 バイト スパン ID (Activity.SpanId) が割り当てられます。 各アクティビティは、トレース ID、独自の span-id、およびその親 (Activity.ParentSpanId) のスパン ID を記録します。 分散トレースはプロセス境界を越えて作業を追跡できるため、親アクティビティと子アクティビティが同じプロセスに含まれていない可能性があります。 トレース ID と親スパン ID の組み合わせにより、親アクティビティが存在するプロセスに関係なく、親アクティビティをグローバルに一意に識別できます。

Activity.DefaultIdFormat は、新しいトレースを開始するために使用する ID 形式を制御しますが、既定では、既存のトレースに新しいアクティビティを追加すると、親アクティビティで使用されている形式が使用されます。 Activity.ForceDefaultIdFormat を true に設定すると、この動作がオーバーライドされ、親が別の ID 形式を使用している場合でも、DefaultIdFormat を使用してすべての新しいアクティビティが作成されます。

アクティビティの開始と停止

プロセス内の各スレッドには、そのスレッドで発生している作業を追跡する対応する Activity オブジェクトがあり、Activity.Current経由でアクセスできます。 現在のアクティビティは、スレッド上のすべての同期呼び出しに自動的に沿って流れ、異なるスレッドで処理される非同期呼び出しに従います。 アクティビティ A がスレッドの現在のアクティビティであり、コードが新しいアクティビティ B を開始する場合、B はそのスレッドの新しい現在のアクティビティになります。 既定では、アクティビティ B はアクティビティ A も親として扱います。 アクティビティ B が後で停止されると、アクティビティ A はスレッド上の現在のアクティビティとして復元されます。 アクティビティが開始されると、現在の時刻が Activity.StartTimeUtcとしてキャプチャされます。 停止すると、Activity.Duration は現在の時刻と開始時刻の差として計算されます。

プロセス境界を越えて調整する

プロセス境界を越えて作業を追跡するには、受信プロセスがそれらを参照するアクティビティを作成できるように、アクティビティの親 ID をネットワーク経由で送信する必要があります。 W3C TraceContext ID 形式を使用する場合、.NET では 標準で推奨されている HTTP ヘッダーを使用して、この情報を転送することもできます。 Hierarchical ID 形式を使用する場合、.NET はカスタム要求 ID HTTP ヘッダーを使用して ID を送信します。 他の多くの言語ランタイムとは異なり、ASP.NET Web サーバーや System.Net.Http などの .NET インボックス ライブラリは、HTTP メッセージでアクティビティ ID をデコードおよびエンコードする方法をネイティブに理解しています。 ランタイムは、同期呼び出しと非同期呼び出しを通じて ID をフローする方法も理解します。 つまり、HTTP メッセージを受信して出力する .NET アプリケーションは、アプリ開発者やサードパーティのライブラリの依存関係による特別なコーディングを行わずに、分散トレース ID のフローに自動的に参加します。 サード パーティ製ライブラリでは、HTTP 以外のメッセージ プロトコル経由で ID を送信したり、HTTP のカスタム エンコード規則をサポートしたりするためのサポートが追加される場合があります。

トレースを収集する

インストルメント化されたコードでは、分散トレースの一部として Activity オブジェクトを作成できますが、トレース全体を後で確認できるように、これらのオブジェクト内の情報を一元化された永続的ストアで送信およびシリアル化する必要があります。 Application Insights、OpenTelemetry、サード パーティのテレメトリまたは APM ベンダーによって提供されるライブラリなど、このタスクを実行できるテレメトリ収集ライブラリがいくつかあります。 または、開発者は、System.Diagnostics.ActivityListener または System.Diagnostics.DiagnosticListenerを使用して、独自のカスタムアクティビティテレメトリコレクションを作成できます。 ActivityListener は、開発者がアクティビティに関する事前知識を持っているかどうかにかかわらず、アクティビティの監視をサポートします。 これにより、ActivityListener はシンプルで柔軟な汎用ソリューションになります。 これに対し、DiagnosticListener の使用は、インストルメント化されたコードが DiagnosticSource.StartActivity を呼び出してオプトインする必要があるより複雑なシナリオであり、コレクション ライブラリでは、インストルメント化されたコードが起動時に使用した正確な名前付け情報を認識する必要があります。 DiagnosticSource と DiagnosticListener を使用すると、作成者とリスナーは任意の .NET オブジェクトを交換し、カスタマイズされた情報の受け渡し規則を確立できます。

サンプリング

高スループット アプリケーションのパフォーマンスを向上させるために、.NET 上の分散トレースでは、すべてのトレースを記録するのではなく、トレースのサブセットのみをサンプリングできます。 推奨される ActivitySource.StartActivity API を使用して作成されたアクティビティの場合、テレメトリ 収集ライブラリは、ActivityListener.Sample コールバックを使用してサンプリングを制御できます。 ログ ライブラリでは、アクティビティをまったく作成せず、トレース ID の分散を伝達したり、完全な診断情報を設定したりするために必要な最小限の情報でアクティビティを作成することを選択できます。 これらの選択肢は、診断ユーティリティを増加させるためにパフォーマンスオーバーヘッドを増加させるトレードオフです。 Activity.ActivityDiagnosticSource.StartActivity を呼び出す古いパターンを使用して開始されたアクティビティでは、最初に DiagnosticSource.IsEnabledを呼び出すことによって DiagnosticListener サンプリングをサポートすることもできます。 完全な診断情報をキャプチャする場合でも、.NET 実装は高速に設計されており、効率的なコレクターと組み合わせて、アクティビティを作成、設定、および最新のハードウェアで約マイクロ秒で送信できます。 サンプリングにより、記録されないアクティビティごとにインストルメンテーション コストを 100 ナノ秒未満に削減できます。

次の手順

.NET アプリケーションで分散トレースの使用を開始するコード例については、分散トレース インストルメンテーションを参照してください。

.NET によってネイティブに出力されるアクティビティの一覧については、「.NETの組み込みアクティビティ 参照してください。