분산 추적 및 원격 분석 상관 관계란?

참고 항목

다음 설명서는 Application Insights 클래식 API를 사용합니다. Application Insights에 대한 장기 플랜은 OpenTelemetry를 사용하여 데이터를 수집하는 것입니다. 자세한 내용은 .NET, Node.js, Python 및 Java 애플리케이션에 대해 Azure Monitor OpenTelemetry 사용을 참조하세요.

최신 클라우드 및 마이크로 서비스 아키텍처를 통해 비용을 절감하면서 가용성과 처리량을 높이는 간단하고 독립적으로 배포할 수 있는 서비스가 가능해졌습니다. 그러나 이로 인해 전체 시스템을 추론하고 디버깅하기가 더 어려워졌습니다. 분산 추적은 클라우드 및 마이크로 서비스 아키텍처에 대한 호출 스택과 같은 성능 프로파일러를 제공하여 이 문제를 해결합니다.

Azure Monitor는 분산 추적 데이터를 사용하는 두 가지 환경(단일 트랜잭션/요청에 대한 트랜잭션 진단 보기와 시스템이 상호 작용하는 방식을 보여 주는 애플리케이션 맵 보기)을 제공합니다.

Application Insights는 각 구성 요소를 개별적으로 모니터링하고 분산 원격 분석 상관 관계를 사용하여 오류 또는 성능 저하를 담당하는 구성 요소를 검색할 수 있습니다. 이 문서에서는 Application Insights에서 사용하는 다양한 언어 및 플랫폼에 대한 데이터 모델, 컨텍스트 전파 기술, 프로토콜 및 상관 관계 전술 구현에 대해 설명합니다.

분산 추적 사용

애플리케이션에 분산 추적을 사용하도록 설정하려면 프로그래밍 언어에 따라 각 서비스에 올바른 에이전트, SDK 또는 라이브러리를 추가합니다.

자동 계측 또는 SDK를 통해 Application Insights로 사용

.NET, .NET Core, Java, Node.js 및 JavaScript용 Application Insights 에이전트 및 SDK는 모두 기본적으로 분산 추적을 지원합니다. 각 Application Insights SDK를 설치 및 구성하는 지침이 다음을 위해 제공됩니다.

적절한 Application Insight SDK가 설치되고 구성되면, 많이 사용되는 프레임워크, 라이브러리 및 기술에 대한 추적 정보가 SDK 종속성 자동 수집기를 통해 자동으로 수집됩니다. 지원되는 기술의 전체 목록은 종속성 자동 수집 설명서에 제공됩니다.

또한 TelemetryClientTrackDependency를 호출하여 원하는 기술을 수동으로 추적할 수 있습니다.

OpenTelemetry를 통해 사용

이제 Application Insights는 OpenTelemetry를 통한 분산 추적을 지원합니다. OpenTelemetry는 Application Insights에 추적, 메트릭 및 로그를 보내는 공급업체 중립적 계측을 제공합니다. 처음에 OpenTelemetry 커뮤니티는 분산 추적을 사용했습니다. 메트릭 및 로그는 아직 진행 중입니다.

완전한 가시성 스토리에는 세 가지 핵심이 모두 포함되어 있습니다. Azure Monitor OpenTelemetry 기반 제품의 상태를 확인하여 포함된 항목, 일반적으로 사용할 수 있는 제품 및 지원 옵션에 대한 최신 상태를 확인합니다.

다음 페이지는 Microsoft의 OpenTelemetry 기반 제품을 사용하도록 설정하고 구성하기 위한 언어별 지침으로 구성되어 있습니다. 중요한 것은 OpenTelemetry가 프로젝트에 적합한지 결정할 수 있도록 각 제품의 사용 가능한 기능과 제한 사항을 공유한다는 것입니다.

OpenCensus를 통해 사용하도록 설정

Application Insights SDK 외에, Application Insights는 OpenCensus를 통해서도 분산 추적을 지원합니다. OpenCensus는 오픈 소스, 벤더에 구애받지 않는, 라이브러리의 단일 배포판이며 서비스에 대한 메트릭 컬렉션 및 분산 추적 기능을 제공합니다. 또한 오픈 소스 커뮤니티에서 Redis, Memcached 또는 MongoDB와 같이 널리 사용되는 기술을 통해 분산 추적이 가능합니다. Microsoft는 여러 다른 모니터링 및 클라우드 파트너와 OpenCensus에 대해 협력하고 있습니다.

Python용 OpenCensus에 대한 자세한 내용은 Python 애플리케이션용 Azure Monitor 설정을 참조하세요.

OpenCensus 웹 사이트는 Python, Go 및 OpenCensus 사용을 위한 다양한 가이드에 대한 API 참조 설명서를 유지 관리합니다.

원격 분석 상관 관계에 대한 데이터 모델

Application Insights는 분산 원격 분석 상관 관계에 대한 데이터 모델을 정의합니다. 원격 분석을 논리 작업과 연결하기 위해 모든 원격 분석 항목에 operation_Id라는 컨텍스트 필드가 있습니다. 분산 추적의 모든 원격 분석 항목은 이 식별자를 공유합니다. 따라서 단일 계층에서 원격 분석이 손실된 경우에도 다른 구성 요소에서 보고한 원격 분석을 연결할 수 있습니다.

분산 논리 작업은 일반적으로 구성 요소 중 하나에서 처리되는 요청인 더 작은 작업의 집합으로 구성됩니다. 요청 원격 분석은 이러한 작업을 정의합니다. 모든 요청 원격 분석 항목에는 글로벌로 고유하게 식별되는 자체의 id가 있습니다. 그리고 요청과 연결된 모든 원격 분석 항목(예: 추적 및 예외)에서 operation_parentId를 요청 id의 값으로 설정해야 합니다.

종속성 원격 분석은 다른 구성 요소에 대한 HTTP 호출과 같은 모든 나가는 작업을 나타냅니다. 전역적으로 고유한 자체 id도 정의합니다. 이 종속성 호출을 통해 시작된 요청 원격 분석은 이 idoperation_parentId로 사용합니다.

operation_Id, operation_parentIdrequest.iddependency.id와 함께 사용하여 분산 논리 작업의 보기를 빌드할 수 있습니다. 또한 이러한 필드는 원격 분석 호출의 인과 관계 순서를 정의합니다.

마이크로 서비스 환경에서 구성 요소의 추적은 다른 스토리지 항목으로 이동할 수 있습니다. 모든 구성 요소는 Application Insights에서 고유한 연결 문자열을 가질 수 있습니다. 논리적 작업에 대한 원격 분석을 가져오기 위해 Application Insights는 모든 스토리지 항목에서 데이터를 쿼리합니다.

스토리지 항목의 수가 많은 경우 다음 항목을 찾을 위치에 대한 힌트가 필요합니다. Application Insights 데이터 모델에서는 이 문제를 해결하기 위해 두 가지 필드, 즉 request.sourcedependency.target을 정의합니다. 첫 번째 필드는 종속성 요청을 시작한 구성 요소를 식별합니다. 두 번째 필드는 종속성 호출의 응답을 반환한 구성 요소를 식별합니다.

app 쿼리 식을 사용하여 서로 다른 여러 인스턴스에서 쿼리하는 방법에 대한 자세한 내용은 Azure Monitor 쿼리의 app() 식을 참조하세요.

예시

예를 살펴보겠습니다. Stock이라는 외부 API를 사용하여 주식의 현재 시가를 보여 주는 '주가(Stock Prices)'라는 애플리케이션입니다. 주가 애플리케이션에는 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
요청 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에는 Application Insights에서 해당 서비스의 원격 분석을 쿼리하여 분산 추적을 빌드할 수 있는 서비스 ID가 포함됩니다.

W3C TraceContext를 사용하는 상관 관계 헤더

Application Insights는 다음을 정의하는 W3C Trace-Context로 전환됩니다.

  • traceparent: 글로벌로 고유한 작업 ID와 호출의 고유 식별자를 전달합니다.
  • tracestate: 시스템 특정 추적 컨텍스트를 전달합니다.

최신 버전의 Application Insights SDK는 Trace-Context 프로토콜을 지원하지만 이를 옵트인해야 할 수도 있습니다. (Application Insights SDK에서 지원하는 이전 상관 관계 프로토콜과의 이전 버전과의 호환성이 유지됩니다.)

요청 ID라고도 하는 상관 HTTP 프로토콜은 더 이상 사용되지 않습니다. 이 프로토콜은 두 가지 헤더를 정의합니다.

  • Request-Id: 호출의 글로벌 고유 ID를 전달합니다.
  • Correlation-Context: 분산 추적 속성의 이름-값 쌍 컬렉션을 전달합니다.

Application Insights에서는 상관 관계 HTTP 프로토콜에 대한 extension(확장)도 정의합니다. Request-Context 이름-값 쌍을 사용하여 즉각적인 호출자 또는 호출 수신자에서 사용하는 속성의 컬렉션을 전파합니다. Application Insights SDK는 이 헤더를 사용하여 dependency.targetrequest.source 필드를 설정합니다.

W3C Trace-Context 및 Application Insights 데이터 모델은 다음과 같은 방식으로 매핑됩니다.

Application Insights W3C TraceContext
RequestDependencyId parent-id
Operation_Id trace-id
Operation_ParentId 이 범위 상위 범위의 parent-id입니다. 루트 범위인 경우 이 필드는 비어 있어야 합니다.

자세한 내용은 Application Insights 원격 분석 데이터 모델을 참조하세요.

.NET 앱에 W3C 분산 추적 지원을 사용하도록 설정

W3C TraceContext 기반 분산 추적은 레거시 Request-Id 프로토콜과의 이전 버전과의 호환성과 함께 모든 최신 .NET Framework/.NET Core SDK에서 기본적으로 사용하도록 설정됩니다.

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>
    

    참고 항목

    이전 버전과의 호환성 모드는 기본적으로 사용하도록 설정되어 있으며, enableW3CBackCompat 매개 변수는 선택 사항입니다. 이전 버전과의 호환성을 해제하려는 경우에만 사용하세요.

    모든 서비스가 W3C 프로토콜을 지원하는 최신 버전의 SDK로 업데이트될 때 이 모드를 해제하는 것이 가장 좋습니다. 가능한 한 빨리 최신 SDK로 이동하는 것이 좋습니다.

들어오는 구성과 나가는 구성이 정확히 동일한지 확인하는 것이 중요합니다.

웹앱에 W3C 분산 추적 지원을 사용하도록 설정

이 기능은 JavaScript에 대해 기본적으로 사용하도록 설정되며, 호스팅 페이지 도메인이 요청이 전송되는 도메인과 동일한 경우 헤더가 자동으로 포함됩니다(예: 호스팅 페이지는 example.com이고 Ajax 요청은 example.com으로 전송됨). 분산 추적 모드를 변경하려면 distributedTracingMode 구성 필드를 사용합니다. AI_AND_W3C는 Application Insights에서 계측한 레거시 서비스와의 이전 버전과의 호환성을 위해 기본적으로 제공됩니다.

XMLHttpRequest 또는 Fetch Ajax 요청이 하위 도메인을 포함한 다른 도메인 호스트로 전송되는 경우 상관 관계 헤더는 기본적으로 포함되지 않습니다. 이 기능을 사용하도록 설정하려면 enableCorsCorrelation 구성 필드true로 설정합니다. enableCorsCorrelationtrue로 설정하면 모든 XMLHttpRequest 및 Fetch Ajax 요청에 상관 관계 헤더가 포함됩니다. 따라서 호출되는 서버의 애플리케이션이 traceparent 헤더를 지원하지 않는 경우 브라우저/버전이 서버에서 허용할 헤더에 따라 요청의 유효성을 검사할 수 있는지 여부에 따라 요청이 실패할 수 있습니다. 구성 필드를 사용하여 correlationHeaderExcludedDomains 구성 요소 간 상관 관계 헤더 삽입에서 서버의 do기본 제외할 수 있습니다. 예를 들어 Auth0 ID 공급자로 전송된 요청에서 상관 관계 헤더를 제외하는 데 사용할 correlationHeaderExcludedDomains: ['*.auth0.com'] 수 있습니다.

Important

상관 관계를 사용하는 데 필요한 모든 구성을 보려면 JavaScript 상관 관계 문서를 참조하세요.

OpenCensus Python의 원격 분석 상관 관계

OpenCensus Python은 추가 구성 없이 W3C Trace-Context를 지원합니다.

참조의 경우 이 GitHub 페이지에서 OpenCensus 데이터 모델을 찾을 수 있습니다.

들어오는 요청 상관 관계

OpenCensus Python은 들어오는 요청의 W3C Trace-Context 헤더와 요청 자체에서 생성된 범위의 상관 관계를 지정합니다. OpenCensus는 인기 있는 웹 애플리케이션 프레임워크인 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)

이 코드는 로컬 컴퓨터에서 샘플 Flask 애플리케이션을 실행하고 8080 포트를 수신합니다. 추적 컨텍스트의 상관 관계를 지정하려면 엔드포인트에 요청을 보냅니다. 이 예에서는 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 리소스의 로그(분석)에서 데이터를 찾을 수 있습니다.

Screenshot that shows Request telemetry in Logs (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 로깅 통합을 설치하여 이러한 특성을 추가합니다. traceId, spanIdtraceSampled(통합 후에 만들어진 로거에만 적용 가능) 특성이 Python LogRecord 개체에 추가됩니다.

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가 있습니다. spanIdhello라는 범위에 속하는 것과 동일합니다.

AzureLogHandler를 사용하여 로그 데이터를 내보낼 수 있습니다. 자세한 내용은 Python 애플리케이션용 Azure Monitor 설정을 참조하세요.

적절한 상관 관계를 위해 한 구성 요소에서 다른 구성 요소로 추적 정보를 전달할 수도 있습니다. 예를 들어, 두 개의 구성 요소(module1module2)가 있는 시나리오를 고려합니다. Module1은 Module2의 함수를 호출합니다. 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 런타임은 ActivityDiagnosticSource를 통해 분산을 지원합니다.

Application Insights .NET SDK는 DiagnosticSourceActivity를 사용하여 원격 분석을 수집하고 상관 관계를 지정합니다.

Java의 원격 분석 상관 관계

Java 에이전트는 원격 분석의 자동 상관을 지원합니다. 요청 범위 내에서 실행된 모든 원격 분석(예: 추적, 예외 및 사용자 지정 이벤트)에 대해 operation_id를 자동으로 채웁니다. 또한 Java SDK 에이전트가 구성된 경우 HTTP를 통한 서비스 간 호출에 대해 앞에서 설명한 상관 관계 헤더를 전파합니다.

참고 항목

Application Insights Java 에이전트는 JMS, Kafka, Netty/Webflux 등에 대한 요청 및 종속성을 자동으로 수집합니다. Java SDK의 경우 상관 관계 기능에 Apache HttpClient를 통해 수행되는 호출만 지원됩니다. 메시징 기술(예: Kafka, RabbitMQ 및 Azure Service Bus) 간 자동 컨텍스트 전파는 SDK에서 지원되지 않습니다.

사용자 지정 원격 분석을 수집하려면 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 이상에서는 ApplicationInsights.xml 파일에 <RoleName>을 추가하여 cloud_RoleName을 지정할 수 있습니다.

    Screenshot that shows Application Insights overview and connection string.

    <?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>

환경 변수 또는 시스템 속성을 통해 클라우드 역할 이름을 설정할 수도 있습니다. 자세한 내용은 클라우드 역할 이름 구성을 참조하세요.

다음 단계