지속성 작업 스케줄러를 사용하여 OpenTelemetry 분산 추적 사용

분산 추적은 오케스트레이션 실행에 대한 엔드 투 엔드 가시성을 제공합니다. 지속성 작업 스케줄러에서 OpenTelemetry를 사용하도록 설정하면 각 오케스트레이션, 작업 및 하위 오케스트레이션은 전체 워크플로에서 타이밍, 순서 및 오류를 표시하는 연결된 범위를 생성합니다. 이러한 추적을 Azure Monitor Application Insights, Jaeger 또는 Zipkin 같은 OpenTelemetry 호환 백 엔드로 내보낼 수 있습니다.

Durable Functions 및 독립 실행형 Durable Task SDK는 Durable Task 스케줄러를 백엔드로 사용할 때 OpenTelemetry 분산 추적을 지원합니다.

작동 방식

Durable Task SDK는 OpenTelemetry 범위를 사용하여 오케스트레이션 및 활동을 자동으로 추적합니다. SDK는 각 오케스트레이션에 대해 부모 범위를 만들고, 각 작업 호출, 하위 오케스트레이션, 타이머에 대해서는 자식 범위를 생성합니다. 추적 컨텍스트는 이러한 모든 작업에 자동으로 전파되므로 전체 워크플로에 대해 상호 관련된 단일 추적을 얻을 수 있습니다.

결과 추적 트리는 다음과 같습니다.

create_orchestration (client)
  └─ orchestration (server)
       ├─ activity:Step1
       ├─ activity:Step2
       └─ activity:Step3

오케스트레이터 또는 활동 코드에 사용자 지정 계측을 추가할 필요가 없습니다. Microsoft.DurableTask OpenTelemetry 구성에 활동 원본을 등록하고 SDK는 나머지를 처리합니다.

사전 요구 사항

  • Durable Functions 확장 버전 2.13.0 이상이 있는 Azure Functions 프로젝트입니다.
  • 지속성 작업 스케줄러는 함수 앱의 스토리지 백 엔드로 구성됩니다.
  • 트레이스를 보기 위한 OpenTelemetry 호환 백엔드(Application Insights, Jaeger 또는 다른 OTLP 수집기)입니다.
  • .NET 8 SDK 이상.
  • Microsoft.DurableTask.Worker.AzureManagedMicrosoft.DurableTask.Client.AzureManaged NuGet 패키지입니다.
  • OpenTelemetry, OpenTelemetry.Extensions.HostingOpenTelemetry.Exporter.OpenTelemetryProtocol NuGet 패키지입니다.
  • 프로덕션용 Application Insights 또는 로컬 개발을 위한 Jaeger 와 같은 추적을 보기 위한 OpenTelemetry 호환 백 엔드입니다.

분산 추적 활성화

Durable Functions의 분산 추적을 사용하도록 설정하려면 host.json을(를) 업데이트하고, OpenTelemetry 호환 원격 분석 백엔드를 구성하십시오.

host.json 업데이트

tracing durableTask 파일 아래에 섹션을 추가합니다.

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "tracing": {
        "DistributedTracingEnabled": true,
        "Version": "V2"
      }
    }
  }
}

Application Insights를 구성하기

함수 앱에서 APPLICATIONINSIGHTS_CONNECTION_STRING 환경 변수를 설정합니다.

로컬 개발의 경우 local.settings.json추가합니다.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "<your-connection-string>"
  }
}

Azure 호스팅 앱의 경우 Azure 포털의 구성 아래에 애플리케이션 설정으로 추가합니다.

메모

이전에 사용한 APPINSIGHTS_INSTRUMENTATIONKEY경우 최신 기능으로 APPLICATIONINSIGHTS_CONNECTION_STRING 전환합니다.

원격 분석 노이즈 줄이기

Application Insights가 추적 데이터를 샘플링하지 못하도록 하려면 Request샘플링 규칙에서 제외 합니다.

{
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  }
}

OpenTelemetry 구성에 Microsoft.DurableTask 활동 원본을 등록하세요. 지속성 작업 SDK는 이 소스를 등록하면 오케스트레이션과 활동에 대한 스팬을 자동으로 생성합니다.

작업자의 Program.cs 파일에 Durable Task 작업 원본을 사용하여 OpenTelemetry 추적을 추가합니다.

using Microsoft.DurableTask;
using Microsoft.DurableTask.Worker;
using Microsoft.DurableTask.Worker.AzureManaged;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = Host.CreateApplicationBuilder(args);

// Configure OpenTelemetry tracing
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri(
                    Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")
                    ?? "http://localhost:4317");
            });
    });

// Build connection string from environment variables
string endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? "http://localhost:8080";
string taskHub = Environment.GetEnvironmentVariable("TASKHUB") ?? "default";
string connectionString = endpoint.Contains("localhost")
    ? $"Endpoint={endpoint};TaskHub={taskHub};Authentication=None"
    : $"Endpoint={endpoint};TaskHub={taskHub};Authentication=DefaultAzure";

// Configure Durable Task worker
builder.Services.AddDurableTaskWorker()
    .AddTasks(tasks =>
    {
        tasks.AddOrchestratorFunc<string, string>(
            "OrderProcessingOrchestration", async (ctx, input) =>
        {
            var validated = await ctx.CallActivityAsync<string>("ValidateOrder", input);
            var payment = await ctx.CallActivityAsync<string>("ProcessPayment", validated);
            var shipment = await ctx.CallActivityAsync<string>("ShipOrder", payment);
            var result = await ctx.CallActivityAsync<string>("SendNotification", shipment);
            return result;
        });

        tasks.AddActivityFunc<string, string>("ValidateOrder", (ctx, input) =>
            Task.FromResult($"Validated({input})"));
        tasks.AddActivityFunc<string, string>("ProcessPayment", (ctx, input) =>
            Task.FromResult($"Paid({input})"));
        tasks.AddActivityFunc<string, string>("ShipOrder", (ctx, input) =>
            Task.FromResult($"Shipped({input})"));
        tasks.AddActivityFunc<string, string>("SendNotification", (ctx, input) =>
            Task.FromResult($"Notified({input})"));
    })
    .UseDurableTaskScheduler(connectionString);

var host = builder.Build();
await host.RunAsync();

핵심 라인은 .AddSource("Microsoft.DurableTask")으로, 이는 OpenTelemetry에게 Durable Task SDK가 생성하는 스팬을 캡처하도록 지시합니다.

OTLP 엔드포인트 구성

위의 코드 조각은 추적 데이터의 대상을 OTEL_EXPORTER_OTLP_ENDPOINT 설정하기 위해 환경 변수를 참조합니다. 백 엔드에 따라 이 변수를 설정합니다.

Backend 엔드포인트 값 프로토콜
Jaeger(로컬) http://localhost:4317 gRPC
Jaeger(로컬, HTTP) http://localhost:4318 HTTP/protobuf
OpenTelemetry 수집기 http://<collector-host>:4317 gRPC
Azure Monitor(OTLP를 통해) 대신 Azure Monitor 내보내기 사용 적용되지 않음 (N/A)

Jaeger를 사용한 로컬 개발의 경우 Jaeger가 OTLP gRPC를 사용하도록 설정된 상태로 실행 중일 때 기본값 http://localhost:4317 이 작동합니다(포트 4317). JavaScript SDK는 기본적으로 HTTP/protobuf를 사용하므로 4318 포트와 /v1/traces 경로를 대상으로 합니다.

Jaeger UI를 사용하여 로컬로 추적 보기

로컬 개발의 경우 Jaeger와 함께 지속성 작업 스케줄러 에뮬레이터를 사용하여 추적을 봅니다. 두 서비스를 모두 시작하려면 다음 docker-compose.yml 을 사용합니다.

services:
  dts-emulator:
    image: mcr.microsoft.com/dts/dts-emulator:latest
    ports:
      - "8080:8080"  # gRPC
      - "8082:8082"  # Dashboard
  jaeger:
    image: jaegertracing/jaeger:latest
    ports:
      - "16686:16686"  # Jaeger UI
      - "4317:4317"    # OTLP gRPC
      - "4318:4318"    # OTLP HTTP

인프라를 시작합니다.

docker compose up -d

애플리케이션을 실행한 후 Jaeger UI를 http://localhost:16686 열고 서비스 이름(예 durable-worker: )을 검색하여 추적을 봅니다.

Durable Functions 로컬 개발을 위해 분산 추적 데이터는 기본적으로 Application Insights로 전송됩니다. 배포하지 않고 로컬로 추적을 보려면 함수 앱의 Program.csApplication Insights와 함께 OTLP 내보내기를 추가할 수 있습니다.

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri("http://localhost:4317");
            });
    });

그런 다음 Jaeger를 로컬 환경에서 docker run -d -p 16686:16686 -p 4317:4317 jaegertracing/jaeger:latest 실행하고 Jaeger UI를 http://localhost:16686에서 엽니다.

Application Insights에서 추적 보기

프로덕션 워크로드의 경우 Application Insights 는 권장되는 원격 분석 백 엔드입니다.

DistributedTracingEnabled에서 trueVersion로 설정하고 V2host.json로 설정하면, 지속성 함수 앱은 Application Insights로 상관된 스팬을 전송합니다. Azure 포털에서 전체 오케스트레이션 추적을 보려면 다음을 수행합니다.

  1. Azure 포털에서 Application Insights 리소스로 이동합니다.
  2. 트랜잭션 검색을 열고 이름 또는 인스턴스 ID별로 오케스트레이션을 검색합니다.
  3. 추적을 선택하여 모든 상관 관계의 범위를 포함한 엔드 투 엔드 트랜잭션을 확인합니다.

추적은 오케스트레이션을 부모 스팬으로 표시하며, 각 활동 호출, 하위 오케스트레이션, 타이머 대기에 대한 자식 스팬을 포함합니다. 다음 패턴은 고유한 추적 셰이프를 생성합니다.

패턴 도형 추적
함수 연결 순차 작업이 오케스트레이터 범위 아래에 중첩되어 있습니다.
팬아웃/팬인 동시에 겹쳐 실행되는 병렬 활동 스팬입니다.
인간 상호 작용 외부 이벤트를 오래 기다리는 오케스트레이터 스팬입니다.
모니터 반복 간격 사이에 타이머 대기가 있는 반복 활동 스팬입니다.

Azure Monitor OpenTelemetry 익스포터를 사용하여 추적을 Application Insights로 전송하도록 OTLP 익스포터를 구성하거나, OTLP를 통해 OpenTelemetry 수집기로 내보내고 이를 Application Insights로 전달하도록 구성합니다.

Azure.Monitor.OpenTelemetry.Exporter NuGet 패키지를 설치하고 OTLP 내보내기를 다음으로 바꿉다.

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddAzureMonitorTraceExporter(opts =>
            {
                opts.ConnectionString = Environment.GetEnvironmentVariable(
                    "APPLICATIONINSIGHTS_CONNECTION_STRING");
            });
    });

추적 데이터에 표시되는 내용

지속성 작업 SDK에서 생성된 추적 데이터에는 다음이 포함됩니다.

범위 유형 설명
create_orchestration 새 오케스트레이션을 스케줄할 때 클라이언트 측에서 생성되는 스팬입니다.
orchestration 전체 실행 수명 주기를 포함하는 서버 쪽 오케스트레이션 범위
activity:<name> 타이밍 및 결과를 보여 주는 각 활동 호출에 대한 범위
sub_orchestration:<name> 각 하위 오케스트레이션 호출에 대한 범위
timer 지속 타이머 대기에 대한 스팬입니다.

각 범위에는 durabletask.type, durabletask.task.name, durabletask.task.instance_id, 및 durabletask.task.task_id와 같은 특성이 포함됩니다. 실패한 활동과 오케스트레이션은 스팬의 상태와 이벤트에 오류 정보를 포함합니다.

Troubleshooting

Issue 해결 방법
흔적이 보이지 않음 활동 원본이 Microsoft.DurableTask 등록되어 있고 내보내기 엔드포인트에 연결할 수 있는지 확인합니다.
추적이 불완전합니다. OpenTelemetry SDK가 지속성 작업 SDK(특히 JavaScript/TypeScript) 전에 초기화되어 있는지 확인합니다.
Application Insights에서 누락된 범위 추적 데이터가 삭제되지 않도록 샘플링 설정을 사용하지 않도록 설정하거나 조정합니다.
추적 로그는 상관 관계가 없습니다. 지속성 작업 스케줄러를 백 엔드로 사용하고 있는지 확인합니다. 추적 컨텍스트 전파에는 스케줄러가 필요합니다.

예제 코드