分散トレースとテレメトリの相関関係

最新のクラウドとマイクロサービス アーキテクチャは、可用性とスループットを向上させながらコストを削減する、シンプルで個別にデプロイ可能なサービスを可能にしました。 しかし、システム全体の判断やデバッグがより難しくなっています。 分散トレースでは、クラウドおよびマイクロサービス アーキテクチャの呼び出し履歴と同様に動作するパフォーマンス プロファイラーを提供することで、この問題を解決します。

Azure Monitor には、分散トレース データを使用するための 2 つのエクスペリエンスが用意されています。1 つのトランザクション/要求のトランザクション診断ビューと、システムでの対話方法を示すアプリケーション マップ ビューです。

Application Insights では、分散テレメトリの相関関係を使用して、各コンポーネントを個別に監視し、障害やパフォーマンスの低下を担当するコンポーネントを検出できます。 この記事では、Application Insights で使用されるさまざまな言語とプラットフォームでのデータ モデル、コンテキスト伝達手法、プロトコル、相関戦術の実装について説明します。

分散トレースを有効にする

アプリケーションの分散トレースを有効にするには、プログラミング言語に基づいて、適切なエージェント、SDK、またはライブラリを各サービスに追加します。

自動インストルメンテーションまたは SDK を使用して Application Insights 経由で有効化する

.NET、.NET Core、Java、Node.js、JavaScript 用の Application Insights エージェントと SDK はすべて、分散トレースをネイティブにサポートしています。 各 Application Insights SDK をインストールおよび構成する手順については、以下から入手できます。

適切な Application Insights SDK がインストールおよび構成されると、トレース情報は、SDK 依存関係の自動コレクターによって一般的なフレームワーク、ライブラリ、テクノロジが自動収集されます。 サポートされるテクノロジの完全なリストは、「依存関係の自動収集」で利用できます。

任意のテクノロジも TelemetryClient 上の TrackDependency への呼び出しによって手動で追跡できます。

OpenTelemetry 経由での有効化

Application Insights で新たに、OpenTelemetry を使用した分散トレースがサポートされるようになりました。 OpenTelemetry は、Application Insights にトレース、メトリック、ログを送信するための、ベンダーに依存しないインストルメンテーションを提供します。 最初に、OpenTelemetry コミュニティは分散トレースを取り上げました。 メトリックとログはまだ進行中です。

完全な可観測性ストーリーには 3 つの重要な要素がすべて含まれますが、現在、.NET、Python、JavaScript 用の Azure Monitor OpenTelemetry ベースのエクスポーター プレビュー オファリングには分散トレースのみが含まれています。 Java OpenTelemetry ベースの Azure Monitor オファリングは一般提供され、完全にサポートされています。

次のページは、Microsoft の OpenTelemetry ベースのオファリングを有効にして構成するための言語ごとのガイダンスで構成されています。 重要なこととして、OpenTelemetry が各プロジェクトに適切かどうかを判定できるように、Microsoft は各オファリングの使用可能な機能や制限事項を共有しています。

OpenCensus を使用して有効にする

Application Insights SDK に加えて、Application Insights では OpenCensus からの分散トレースもサポートされます。 OpenCensus はオープンソースで、ベンダーに捕らわれない単一のディストリビューションのライブラリであり、サービスにメトリック コレクションと分散トレースを提供します。 また、オープンソース コミュニティを有効にして、Redis、Memcached、または MongoDB などの一般的なテクノロジで分散トレースを有効にすることもできます。 Microsoft では、その他のいくつかの監視やクラウド パートナーを使って OpenCensus で共同作業を行うことができます

OpenCensus for Python の詳細については、「Python アプリケーション用に Azure Monitor をセットアップします」を参照してください。

OpenCensus の Web サイトには、PythonGo 向けの API リファレンス ドキュメント、および OpenCensus を使用するためのさまざまなガイドがあります。

テレメトリの関連付けのためのデータ モデル

Application Insights は、分散しているテレメトリを相関付けるためのデータ モデルを定義しています。 テレメトリを論理操作と関連付けるために、すべてのテレメトリ項目には operation_Id と呼ばれるコンテキスト フィールドがあります。 分散トレース内のすべてのテレメトリ項目で、この ID が共有されます。 このため、1 つのレイヤーからテレメトリが失われた場合でも、他のコンポーネントから報告されたテレメトリを関連付けることができます。

分散型論理操作は、通常は、一連の小さな操作 (いずれかのコンポーネントによって処理される要求) で構成されます。 要求テレメトリによって、これらの操作が定義されます。 すべての要求テレメトリ項目には、それをグローバルに一意に識別する独自の id があります。 要求に関連付けられているすべてのテレメトリ項目 (トレースや例外など) では、operation_parentId を要求の id 値に設定する必要があります。

依存関係テレメトリは、すべての発信操作 (別のコンポーネントに対する HTTP 呼び出しなど) を表します。 さらに、グローバルに一意である独自の id を定義します。 この依存関係呼び出しによって開始された要求テレメトリでは、この id をその operation_parentId として使用します。

operation_Idoperation_parentId、および request.iddependency.id と共に使用して、分散型論理操作のビューを構築できます。 これらのフィールドでは、テレメトリ呼び出しの因果関係の順序も定義します。

マイクロ サービス環境では、コンポーネントからのトレースがさまざまなストレージ項目に送信される可能性があります。 すべてのコンポーネントが、Application Insights 内に独自の接続文字列を持つことができます。 論理操作のテレメトリを取得するために、Application Insights では、すべてのストレージ項目に対してデータのクエリが実行されます。

ストレージ項目の数が膨大な場合は、次に検索する場所に関するヒントが必要になります。 Application Insights データ モデルでは、この問題を解決するために request.sourcedependency.target という 2 つのフィールドが定義されています。 最初のフィールドでは、依存関係の要求を開始したコンポーネントを特定します。 2 番目のフィールドでは、依存関係の呼び出しの応答を返したコンポーネントを特定します。

app クエリ式を使用して複数の異なるインスタンスからクエリを実行する方法については、「Azure Monitor クエリでの app() 式」を参照してください。

1 つ例を見てみましょう。 Stock Prices という名前アプリケーションでは、Stock という名前の外部 API を使用して株の現在の市場価格を表示します。 Stock Prices アプリケーションには、クライアント Web ブラウザーが GET /Home/Stock を使用して開く、Stock ページという名前のページがあります。 アプリケーションにより、HTTP 呼び出し GET /api/stock/value を使用して Stock API にクエリが実行されます。

結果として生成されたテレメトリを、クエリを実行して分析できます。

(requests | union dependencies | union pageViews)
| where operation_Id == "STYz"
| project timestamp, itemType, name, id, operation_ParentId, operation_Id

結果では、すべてのテレメトリ項目がルートの operation_Id を共有しています。 ページから Ajax の呼び出しが行われると、新しい一意の ID (qJSXU) が依存関係テレメトリに割り当てられ、pageView の ID が operation_ParentId として使用されます。 その後、サーバー要求で Ajax の ID が operation_ParentId として使用されます。

itemType name id operation_ParentId operation_Id
pageView Stock page STYz STYz
dependency GET /Home/Stock qJSXU STYz STYz
request GET Home/Stock KqKwlrSt9PA= qJSXU STYz
dependency GET /api/stock/value bBrf2L7mm2g= KqKwlrSt9PA= STYz

呼び出し GET /api/stock/value が外部サービスに対して行われる場合、dependency.target フィールドを適切に設定できるように、該当のサーバーの ID を把握しておく必要があります。 外部サービスが監視をサポートしていない場合、target は、サービスのホスト名に設定されます。 たとえば stock-prices-api.com です。 しかし、そのサービスが定義済みの HTTP ヘッダーを返すことでそれ自体を識別している場合、target にはサービスの ID が含まれます。Application Insights はそれを使用して、そのサービスに対してテレメトリのクエリを実行することによって分散トレースを構築できます。

W3C TraceContext を使用した相関付けヘッダー

Application Insights では、以下を定義する W3C Trace-Context に移行しています。

  • traceparent:呼び出しのグローバルに一意の操作 ID と一意識別子を記述します。
  • tracestate:システム固有のトレース コンテキストを記述します。

Application Insights SDK の最新バージョンでは Trace-Context プロトコルがサポートされますが、それを利用する必要が生じる場合があります (Application Insights SDK によってサポートされている以前の相関付けプロトコルによる下位互換性は、引き続き利用できます)。

相関付け HTTP プロトコル (Request-Id とも呼ばれます) は、非推奨になる予定です。 このプロトコルは、2 つのヘッダーを定義しています。

  • Request-Id:呼び出しのグローバルに一意の ID を記述します。
  • Correlation-Context:分散トレースのプロパティの名前と値のペアのコレクションを記述します。

Application Insights では、相関付け HTTP プロトコル用の拡張機能も定義されています。 これは Request-Context の名前と値のペアを使用して、直接の呼び出し元または呼び出し先によって使用されたプロパティのコレクションを伝達します。 Application Insights SDK は、このヘッダーを使用して、dependency.target フィールドと request.source フィールドを設定します。

W3C Trace-Context と Application Insights のデータ モデル マップを次に示します。

Application Insights W3C TraceContext
RequestDependencyId parent-id
Operation_Id trace-id
Operation_ParentId この範囲の親範囲の parent-id。 ルート範囲の場合は、このフィールドを空にする必要があります。

詳細については、「Application Insights Telemetry のデータ モデル」をご覧ください。

.NET アプリの W3C 分散トレース サポートを有効にする

W3C TraceContext ベースの分散トレースは、最近のすべての .NET Framework/.NET Core SDK で既定で有効になっていることに加え、従来の Request-Id プロトコルとの下位互換性があります。

Java アプリの W3C 分散トレース サポートを有効にする

Java 3.0 エージェント

Java 3.0 エージェントでは、既定で W3C がサポートされ、追加の構成は必要ありません。

Java SDK

  • 受信の構成

    Java EE アプリの場合は、ApplicationInsights.xml 内の <TelemetryModules> タグに次のコードを追加します。

    <Add type="com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule>
       <Param name = "W3CEnabled" value ="true"/>
       <Param name ="enableW3CBackCompat" value = "true" />
    </Add>
    

    Spring Boot アプリの場合は、次のプロパティを追加します。

    • azure.application-insights.web.enable-W3C=true
    • azure.application-insights.web.enable-W3C-backcompat-mode=true
  • 送信の構成

    AI-Agent.xml に次のコードを追加します。

    <Instrumentation>
      <BuiltIn enabled="true">
        <HTTP enabled="true" W3C="true" enableW3CBackCompat="true"/>
      </BuiltIn>
    </Instrumentation>
    

    Note

    下位互換性モードは既定で有効になっており、enableW3CBackCompat パラメーターは省略可能です。 これは下位互換性をオフにする場合にのみ使用してください。

    ご利用のすべてのサービスが W3C プロトコルをサポートする新しいバージョンの SDK に更新されたときに、このモードをオフにするのが理想的です。 できるだけ早く、これらの新しい SDK に移行することを強くお勧めします。

受信と送信の構成がまったく同じであることを確認することが重要です。

Web アプリの W3C 分散トレース サポートを有効にする

この機能は Microsoft.ApplicationInsights.JavaScript にあります。 既定では無効になっています。 有効にするには、distributedTracingMode config を使用します。AI_AND_W3C は、Application Insights によってインストルメント化されたレガシ サービスとの下位互換性のために提供されています。

重要

相関付けを有効にするために必要なすべての構成を表示するには、JavaScript の相関付けに関するドキュメントを参照してください。

OpenCensus Python におけるテレメトリの相関付け

OpenCensus Python は、追加の構成を必要とすることなく、W3C Trace-Context をサポートします。

参考までに、OpenCensus データ モデルはこの GitHub ページに掲載されています。

着信要求の相関付け

OpenCensus Python は、受信要求の W3C Trace-Context ヘッダーを、要求自体から生成された範囲に関連付けます。 OpenCensus では、一般的な Web アプリケーション フレームワーク (Flask、Django、Pyramid) の統合によって自動的に相関付けします。 W3C Trace-Context ヘッダーを正しい形式で入力して、要求と共に送信するだけでかまいません。

このサンプル Flask アプリケーションを調べる。 Flask と OpenCensus に加え、Flask と Azure の拡張機能をインストールします。


pip install flask opencensus opencensus-ext-flask opencensus-ext-azure

Application Insights 接続文字列を環境変数に追加する必要があります。

APPLICATIONINSIGHTS_CONNECTION_STRING=<appinsights-connection-string>

サンプル Flask アプリケーション

from flask import Flask
from opencensus.ext.azure.trace_exporter import AzureExporter
from opencensus.ext.flask.flask_middleware import FlaskMiddleware
from opencensus.trace.samplers import ProbabilitySampler

app = Flask(__name__)
middleware = FlaskMiddleware(
    app,
    exporter=AzureExporter(
        connection_string='<appinsights-connection-string>', # or set environment variable APPLICATION_INSIGHTS_CONNECTION_STRING
    ), 
    sampler=ProbabilitySampler(rate=1.0),
)

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='localhost', port=8080, threaded=True)

このコードは、ポート 8080 をリッスンして、サンプルの Flask アプリケーションをローカル コンピューター上で実行します。 トレース コンテキストを関連付けるために、エンドポイントに要求を送信します。 この例では、curl コマンドを使用できます。

curl --header "traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" localhost:8080

Trace-Context ヘッダー形式を見ると、次の情報が得られます。

version: 00

trace-id: 4bf92f3577b34da6a3ce929d0e0e4736

parent-id/span-id: 00f067aa0ba902b7

trace-flags: 01

Azure Monitor に送信された要求エントリを確認すると、トレース ヘッダー情報が入力されたフィールドを確認できます。 このデータは、Azure Monitor Application Insights リソースの [ログ (Analytics)] の下にあります。

[ログ (Analytics)] の要求テレメトリを示すスクリーンショット。

id フィールドの形式は <trace-id>.<span-id> です。ここで、trace-id は要求で渡されたトレース ヘッダーから取得され、span-id はこのスパンで生成された 8 バイト配列です。

operation_ParentId フィールドの形式は <trace-id>.<parent-id> です。ここで、trace-idparent-id は、要求で渡されたトレース ヘッダーから取得されます。

ログの関連付け

OpenCensus Python を使用すると、トレース ID、スパン ID、およびサンプリング フラグをログ レコードに追加することで、ログを関連付けることができます。 OpenCensus のログ統合をインストールすることで、これらの属性を追加します。 Python の LogRecord オブジェクトには、traceIdspanIdtraceSampled の属性が追加されます (統合後に作成されたロガーにのみ適用されます)。

OpenCensus ログ統合をインストールします。

python -m pip install opencensus-ext-logging

サンプル アプリケーション

import logging

from opencensus.trace import config_integration
from opencensus.trace.samplers import AlwaysOnSampler
from opencensus.trace.tracer import Tracer

config_integration.trace_integrations(['logging'])
logging.basicConfig(format='%(asctime)s traceId=%(traceId)s spanId=%(spanId)s %(message)s')
tracer = Tracer(sampler=AlwaysOnSampler())

logger = logging.getLogger(__name__)
logger.warning('Before the span')
with tracer.span(name='hello'):
    logger.warning('In the span')
logger.warning('After the span')

このコードを実行すると、コンソール上に次の情報が表示されます。

2019-10-17 11:25:59,382 traceId=c54cb1d4bbbec5864bf0917c64aeacdc spanId=0000000000000000 Before the span
2019-10-17 11:25:59,384 traceId=c54cb1d4bbbec5864bf0917c64aeacdc spanId=70da28f5a4831014 In the span
2019-10-17 11:25:59,385 traceId=c54cb1d4bbbec5864bf0917c64aeacdc spanId=0000000000000000 After the span

スパン内にあるログ メッセージには、spanId が存在することがわかります。 spanId は、hello という名前のスパンに属するものと同じです。

AzureLogHandler を使用して、ログ データをエクスポートできます。 詳細については、「Python アプリケーション用に Azure Monitor をセットアップします」を参照してください。

また、適切な相関付けのために、あるコンポーネントから別のものにトレース情報を渡すこともできます。 たとえば、module1module2 の 2 つのコンポーネントがあるシナリオについて考えてみます。 Module1 から Module2 の関数が呼び出されます。 1 つのトレースで module1module2 の両方からログを取得するには、次の方法を使用できます。

# module1.py
import logging

from opencensus.trace import config_integration
from opencensus.trace.samplers import AlwaysOnSampler
from opencensus.trace.tracer import Tracer
from module_2 import function_1

config_integration.trace_integrations(["logging"])
logging.basicConfig(
    format="%(asctime)s traceId=%(traceId)s spanId=%(spanId)s %(message)s"
)
tracer = Tracer(sampler=AlwaysOnSampler())

logger = logging.getLogger(__name__)
logger.warning("Before the span")

with tracer.span(name="hello"):
    logger.warning("In the span")
    function_1(logger, tracer)
logger.warning("After the span")
# module_2.py
import logging

from opencensus.trace import config_integration
from opencensus.trace.samplers import AlwaysOnSampler
from opencensus.trace.tracer import Tracer

config_integration.trace_integrations(["logging"])
logging.basicConfig(
    format="%(asctime)s traceId=%(traceId)s spanId=%(spanId)s %(message)s"
)
logger = logging.getLogger(__name__)
tracer = Tracer(sampler=AlwaysOnSampler())


def function_1(logger=logger, parent_tracer=None):
    if parent_tracer is not None:
        tracer = Tracer(
            span_context=parent_tracer.span_context,
            sampler=AlwaysOnSampler(),
        )
    else:
        tracer = Tracer(sampler=AlwaysOnSampler())

    with tracer.span("function_1"):
        logger.info("In function_1")

.NET におけるテレメトリの相関付け

相関付けは、既定ではアプリのオンボード時に処理されます。 特別なアクションは必要ありません。

.NET ランタイムは、アクティビティDiagnosticSource を使用した配布をサポートしています。

Application Insights .NET SDK は、DiagnosticSourceActivity を使用して、テレメトリを収集し、相関付けます。

Java におけるテレメトリの相関付け

Java エージェントでは、テレメトリの自動関連付けがサポートされています。 要求のスコープ内で発行されたすべてのテレメトリ (トレース、例外、カスタム イベントなど) に対して operation_id が自動的に設定されます。 また、Java SDK エージェントが構成されている場合は、相関付けヘッダーも伝達されます。これは、HTTP 経由でのサービス間呼び出しについて先ほど説明したものです。

Note

Application Insights Java エージェントでは、JMS、Kafka、Netty/Webflux などの要求と依存関係が自動収集されます。 Java SDK については、関連付け機能では、Apache HttpClient を使用して行われた呼び出しのみがサポートされます。 SDK では、Kafka、RabbitMQ、Azure Service Bus などのメッセージング テクノロジ間のコンテキスト自動伝達はサポートされていません。

カスタム テレメトリを収集するには、Java 2.6 SDK を使用してアプリケーションをインストルメント化する必要があります。

ロール名

アプリケーション マップにコンポーネント名を表示する方法をカスタマイズする必要が生じる場合があります。 そのためには、次のいずれかのアクションを実行して、cloud_RoleName を手動で設定します。

  • Application Insights Java の場合は、クラウド ロール名を次のように設定します。

    {
      "role": {
        "name": "my cloud role name"
      }
    }
    

    環境変数 APPLICATIONINSIGHTS_ROLE_NAME を使用して、クラウド ロール名を設定することもできます。

  • Application Insights Java SDK 2.5.0 以降では、<RoleName>ApplicationInsights.xml ファイルに追加することで、cloud_RoleName を指定できます。

    Application Insights の概要と接続文字列を示すスクリーンショット。

    <?xml version="1.0" encoding="utf-8"?>
    <ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings" schemaVersion="2014-05-30">
       <ConnectionString>InstrumentationKey=00000000-0000-0000-0000-000000000000</ConnectionString>
       <RoleName>** Your role name **</RoleName>
       ...
    </ApplicationInsights>
    
  • Application Insights Spring Boot スターターで Spring Boot を使用する場合は、application.properties ファイルにアプリケーションのカスタム名を設定します。

    spring.application.name=<name-of-app>

また、環境変数またはシステム プロパティでクラウド ロール名を設定することもできます。 詳細については、クラウド ロール名の構成に関する記事を参照してください。

次のステップ