엔지니어링

분산 추적, OpenTracing 및 Elastic APM

마이크로서비스의 시대

기업은 갈수록 마이크로서비스 아키텍처 도입을 가속화하고 있으며, 매일 더 많은 마이크로서비스를 개발하고 배포하고 있습니다. 이러한 서비스는 다양한 프로그램 언어로 개발되어, 개별 런타임 컨테이너에 배포되고, 각기 다른 팀과 조직에서 관리하는 경우가 많습니다. Twitter와 같은 대기업은 수만 개의 마이크로서비스를 보유하고 이를 함께 연동하여 비즈니스 목표를 실현할 수 있습니다. 이 Twitter 블로그 게시물에 나와 있듯이 Twitter의 전반적인 안정성과 효율성을 높일 뿐만 아니라 문제의 근본 원인을 신속하게 파악하려면 다양한 서비스 토폴로지의 상태 및 성능에 대한 가시성을 확보하는 것이 매우 중요합니다.

바로 분산 추적이 실제로 도움이 될 수 있는 부분입니다. 분산 추적은 마이크로서비스가 직면한 두 가지 근본적인 문제를 해결할 수 있습니다.

  1. 지연 시간 추적
    하나의 사용자 요청 또는 트랜잭션은 서로 다른 런타임 환경에서 다양한 서비스를 통해 이동할 수 있습니다. 특정 요청에 대한 각 서비스의 지연 시간을 이해하는 것은 시스템 전체의 전반적인 성능 특성을 이해하는 데 매우 중요하며 개선 가능한 부분에 대한 귀중한 통찰력을 제공합니다.
  2. 근본 원인 분석
    마이크로서비스의 대규모 에코시스템을 기반으로 구축된 애플리케이션의 경우 근본 원인 분석이 훨씬 더 어렵습니다. 언제든 어떤 서비스에서나 문제가 발생할 수 있습니다. 분산 추적은 이러한 시스템에서 문제를 디버깅할 때 매우 중요한 역할을 합니다.

크게 보면 추적가관측성의 3가지 기둥, 즉 로깅, 메트릭 및 추적이라는 퍼즐의 한 조각에 불과합니다. 간략하게 설명하겠지만 Elastic Stack은 가관측성의 3가지 기둥 모두를 위한 통합 플랫폼입니다. 로그, 메트릭 및 APN 데이터를 동일한 리포지토리에 저장하고, 분석하고, 상호 연관시키면 비즈니스 애플리케이션 및 시스템에 대해 컨텍스트가 가장 풍부한 통찰력을 얻을 수 있습니다. 이 블로그에서는 추적 측면에만 초점을 맞추도록 하겠습니다.

Elastic APM을 사용한 분산 추적

Elastic APM은 Elastic Stack에 구축된 애플리케이션 성능 모니터링 시스템입니다. 이 시스템을 사용하면 수신되는 요청, 데이터베이스 쿼리, 캐시 호출, 외부 HTTP 요청 등의 응답 시간에 대한 자세한 성능 정보를 수집하여 소프트웨어 서비스 및 애플리케이션을 실시간으로 모니터링할 수 있습니다. Elastic APM 에이전트는 지원되는 프레임워크와 기술에 대해 즉시 사용할 수 있는 다양한 자동 계측 도구(예: db 쿼리 타이밍 등)를 제공합니다. 또한, 원하는 용도에 맞춰 사용자 정의 계측 도구를 사용할 수 있습니다. 따라서 성능 문제를 훨씬 더 쉽고 빠르게 파악하고 해결할 수 있습니다.

Elastic APM은 분석 추적을 지원하며 OpenTracing과 호환됩니다. 또한, 마이크로서비스 아키텍처 전반에 걸친 성능을 모두 한곳에서 분석할 수 있습니다. Elastic APM은 프론트엔드 서비스에 대한 초기 웹 요청부터 백엔드 서비스에 대한 쿼리에 이르기까지 모든 요청을 추적하여 이를 수행합니다. 따라서 애플리케이션 전체에서 잠재적 병목 지점을 훨씬 더 쉽고 빠르게 찾을 수 있습니다. APM UI의 타임라인 시각화는 추적에서 서로 연결된 개별 서비스의 모든 트랜잭션을 폭포 보기로 보여줍니다.

Elastic Stack은 로그 집계 및 메트릭 분석에 매우 적합한 플랫폼입니다. 로그, 메트릭 및 APN 추적을 모두 Elasticsearch에 저장하고 색인할 수 있다는 것은 매우 강력한 기능입니다. 인프라 메트릭, 로그 및 추적과 같은 데이터 소스를 신속하게 상호 연관시킬 수 있으므로 근본 원인을 훨씬 더 빠르게 디버깅할 수 있습니다. APM UI에서 추적을 살펴볼 때 호스트 또는 컨테이너 메트릭 및 로그가 수집되어 있는 경우 Actions 메뉴를 클릭하면 이러한 메트릭 및 로그로 신속하게 이동할 수 있습니다.

모든 사람이 Elastic APM을 사용하여 애플리케이션과 서비스를 계측한다면 정말 좋겠지만, 현재 사용할 수 있는 분산 추적 솔루션이 Elastic APM만 있는 것은 아닙니다. Zipkin 및 Jaeger와 같은 다른 인기 있는 오픈 소스 추적 솔루션이 있습니다. 다중 언어 프로그래밍(polyglot programming) 및 다중 언어 지속성(polyglot persistence)과 같은 개념은 잘 알려져 있으며 마이크로서비스 분야에서 이를 받아들이고 있습니다. 이와 마찬가지로 “다중 언어 추적(polyglot tracing)”이 일반화될 것입니다. 마이크로서비스의 독립적이고 분리된 특성 때문에 서로 다른 서비스를 담당하는 사람들이 각기 다른 추적 시스템을 사용할 가능성이 높습니다.

개발자의 당면 과제

사용할 수 있는 추적 시스템이 다양하기 때문에 개발자는 어려운 문제에 직면하게 됩니다. 결국 가장 중요한 것은 추적 솔루션이 애플리케이션 코드 내에 상주한다는 것입니다. 다음은 몇 가지 일반적인 문제입니다.

  1. 어떤 추적 시스템을 사용해야 하나요?
  2. 추적 솔루션을 변경하려면 어떻게 해야 하나요? 전체 소스 코드를 변경하고 싶지 않습니다.
  3. 서로 다른 추적 솔루션을 사용하고 있을지 모르는 공유 라이브러리는 어떻게 해야 하나요?
  4. 타사 서비스에서 다른 추적 솔루션을 사용하는 경우에는 어떻게 해야 하나요?

이러한 문제를 해결하기 위해서는 당연히 표준화가 필요합니다. 표준화 진행 상황에 대해 논의하기 전에, 한걸음 물러서서 아키텍처 관점에서 전체론적으로 분산 추적을 살펴보고 분산 추적의 ‘최고 경지’에 도달하려면 무엇이 필요한지 알아보겠습니다.

분산 추적의 아키텍처 구성 요소

현대적 소프트웨어 시스템은 일반적으로 서로 다른 조직에서 설계하고 개발하여 여러 런타임 환경에서 실행되는 몇 가지 개괄적인 구성 요소로 나눌 수 있습니다.

  • 자체 애플리케이션 코드 및 서비스
  • 공유 라이브러리 및 서비스
  • 외부 서비스

분석 추적을 통해 이러한 시스템을 전체적이고 통합된 방식으로 모니터링하려면 다음과 같은 4가지 아키텍처 구성 요소가 필요합니다.

  1. 표준화된 분산 추적 API. 표준화된 공급업체 중립적인 추적 API를 사용하면 개발자가 표준화된 방식으로 코드를 계측할 수 있으며, 나중에 런타임 시 어떤 추적 솔루션을 사용하는지는 중요하지 않습니다. 이는 모든 작업의 첫 단계입니다.
  2. 표준화된 추적 컨텍스트 정의 및 전파. 한 런타임에서 다른 런타임으로 추적을 계속 진행할 수 있으려면 양쪽에서 추적 컨텍스트를 이해해야 하며 해당 컨텍스트를 전파하는 표준 방법이 있어야 합니다. 최소한, 컨텍스트에는 추적 ID가 포함되어야 합니다.
  3. 표준화된 추적 데이터 정의. 한 추적 솔루션의 추적 데이터를 다른 추적 솔루션에서 이해하고 사용할 수 있으려면 표준화되고 확장 가능한 형식이 있어야 합니다.
  4. 상호 운용 가능한 추적 솔루션. 마지막으로 100% 런타임 호환성을 달성하려면 서로 다른 추적 솔루션에서 다른 추적 솔루션의 추적 데이터를 개방된 방식으로 가져오고 내보낼 수 있는 메커니즘을 제공해야 합니다. 이상적으로는 Jaeger와 같은 추적 솔루션으로 계측하는 공유 라이브러리 또는 서비스는 구성 변경을 통해 Jaeger 에이전트를 사용하여 Elastic APM 또는 다른 추적 솔루션으로 추적 데이터를 직접 보낼 수 있어야 합니다.

이제 OpenTracing을 살펴보겠습니다.

OpenTracing 사양

OpenTracing 사양은 분산 추적을 위한 공급업체 중립적인 개방형 API를 정의합니다. 이는 사용자가 언제든 OpenTracing 구현 업체를 바꿀 수 있도록 함으로써 공급업체에 종속되는 것을 방지합니다. 또한, 프레임워크 및 공유 라이브러리 개발자가 표준 방식으로 즉시 사용할 수 있는 추적 기능을 제공하여 프레임워크와 라이브러리에 대한 통찰력을 향상할 수 있도록 지원합니다. Uber 및 Yelp와 같은 웹 규모 기업은 고도로 분산되고 동적인 애플리케이션에 대한 더 심층적인 가시성을 확보하기 위해 OpenTracing을 사용하고 있습니다.

OpenTracing 데이터 모델

OpenTracing의 기본 개념과 기본 데이터 모델은 Google의 Dapper paper를 기반으로 합니다. 주요 개념으로는 추적과 범위가 있습니다.

  1. 추적은 분산 시스템 전체에 걸쳐 이동하는 트랜잭션을 나타냅니다. 범위의 방향성 비순환 그래프(DAG)라고 생각할 수 있습니다.
  2. 범위는 이름, 시작 시간 및 기간이 있는 작업의 논리적 단위를 나타냅니다. 범위는 모델 관계에 따라 중첩되고 정렬될 수 있습니다. 범위는 특정 범위 인스턴스에 연결된 세분화되고 타임스탬프가 지정된 정형 로그와 더불어 키:값 태그를 허용합니다.
  3. 추적 컨텍스트는 네트워크 또는 메시지 버스를 통해 서비스에서 서비스로 전달하는 시점을 비롯하여 분산 트랜잭션에 수반되는 추적 정보입니다. 이 컨텍스트에는 추적 식별자, 범위 식별자, 그리고 추적 시스템이 다운스트림 서비스로 전파해야 하는 기타 데이터가 포함됩니다.

이 모든 것이 어떻게 작동합니까?

원칙적으로는 표준화를 통해 서로 다른 조직에서 개발하여 실행하는 사용자 정의 애플리케이션 코드, 공유 라이브러리 및 공유 서비스의 추적 정보를 교환할 수 있고 런타임 호환 가능하며 각 구성 요소에서 어떤 추적 솔루션을 사용하든 상관이 없어야 합니다.

그러나 OpenTracing은 앞에서 언급한 4가지 아키텍처 구성 요소 중 첫 번째만 다룹니다. 그렇다면 현재 다른 구성 요소의 상황은 어떻고 미래는 어떻게 될까요?

현재 상황은?

설명했듯이 OpenTracing은 서로 다른 추적 솔루션을 구현할 수 있도록 표준 추적 API 세트를 정의하며, 이는 좋은 출발점이자 매우 고무적인 기능입니다. 그러나 추적 솔루션들이 서로 호환되고 교환 가능하게 하려면 여전히 추적 컨텍스트 표준화 및 추적 데이터 표준화가 필요합니다.

  1. OpenTracing API는 표준 API 세트를 제공합니다. 이는 현재 구현된 유일한 표준화라고 할 수 있고, 사양에도 제한이 있습니다. 예를 들어 모든 프로그래밍 언어를 지원하지 않습니다. 그럼에도 불구하고 멋진 시도였고 큰 관심을 얻고 있습니다.
  2. 표준화된 추적 컨텍스트 정의가 아직 없습니다. W3C 분산 추적 작업 그룹에서 추적 컨텍스트 정의, 즉 W3C 추적 컨텍스트 사양을 표준화하는 중입니다. 이 사양에서는 분산 시스템 내 컨텍스트 및 이벤트 상관관계에 대한 통합 접근 방식을 정의하며, 서로 다른 모니터링 도구 전체에 걸쳐 분산 애플리케이션 내에서 엔드 투 엔드 트랜잭션 추적을 지원합니다. Elastic APM은 분산 추적을 위해 HTTP 헤더 형식을 표준화하려는 W3C 추적 컨텍스트 작업 그룹의 노력을 지원합니다. 자사의 에이전트 구현은 추적 컨텍스트 사양 초안을 충실히 따르고 있으며 최종 사양을 모두 지원할 계획입니다.

    현재 추적 컨텍스트의 비호환성 예로는 다음과 같이 Elastic APM과 Jaeger에서 추적 ID로 사용하는 HTTP 헤더를 들 수 있습니다. 보시다시피 두 ID의 이름과 인코딩이 모두 다릅니다. 서로 다른 추적 헤더가 사용되는 경우, 해당 추적 도구의 범위를 넘어서는 순간 추적이 중단됩니다.

    Jaeger:
    uber-trace-id: 118c6c15301b9b3b3:56e66177e6e55a91:18c6c15301b9b3b3:1

    Elastic APM:
    elastic-apm-traceparent: 00-f109f092a7d869fb4615784bacefcfd7-5bf936f4fcde3af0-01

    정의 자체 외에도 다른 당면 과제들이 있습니다. 예를 들어 모든 HTTP 헤더가 서비스 인프라 및 라우터 등에 의해 자동으로 전달되는 것은 아닙니다. 헤더가 중단될 때마다 추적도 중단됩니다.
  3. 표준화된 추적 데이터 정의가 아직 없습니다. W3C 분산 추적 작업 그룹에서 언급한 것처럼 추적 상호 운용성을 위한 퍼즐의 두 번째 조각은 “추가 해석을 위해 도구 간에 추적 데이터(전체 또는 추적 일부)를 공유할 수 있는 표준화되고 확장 가능한 형식”입니다. 상상할 수 있다시피, 많은 오픈 소스 및 상용 업체가 관련되어 있기 때문에 표준 형식에 합의하는 것은 쉬운 일이 아닙니다. 곧 합의를 이룰 수 있기를 기대합니다.
  4. 추적 솔루션이 런타임 동안 호환되지 않습니다. 위에서 설명한 모든 것과 더불어 시스템을 개방형으로 만들고 다른 시스템과 호환 가능하게 만들려는 엇갈린 동기로 인해 현재 추적 솔루션은 런타임 동안 서로 호환되지 않습니다. 저는 한동안 이 상태가 유지될 것이라고 자신 있게 말할 수 있습니다.

현재 Elastic APM을 다른 추적 솔루션과 연동하는 방법

아직 추적 솔루션의 100% 호환성과는 거리가 멀지만, 실망할 필요는 없습니다. Elastic Stack은 몇 가지 다른 방법으로 다른 추적 솔루션과 연동할 수 있습니다.

  1. 다른 추적 솔루션의 확장 가능한 백엔드 데이터 스토어로서의 Elasticsearch.

    Elasticsearch는 놀라운 확장성과 풍부한 분석 기능 때문에 Zipkin 및 Jaeger와 같은 다른 추적 솔루션의 백엔드 데이터 스토어로 사용되었습니다. 각각 간단한 구성을 통해 Zipkin 또는 Jaeger 추적 데이터를 Elasticsearch로 전송할 수 있습니다. 추적 데이터가 Elasticsearch에 도달하면, Kibana의 강력한 분석 및 시각화 기능을 사용하여 추적 정보를 분석하고 애플리케이션 성능에 대한 깊은 통찰력을 제공하는 눈길을 끄는 시각화 자료를 만들 수 있습니다.
  2. Elastic OpenTracing 브리지

    Elastic APM OpenTracing 브리지를 사용하면 OpenTracing API를 통해 Elastic APM 트랜잭션 및 범위를 생성할 수 있습니다. 다시 말해, OpenTracing API에 대한 호출을 Elastic APM으로 변환하므로 기존 계측 도구를 재사용할 수 있습니다. 예를 들어 코드 몇 줄만 변경하면 Jaeger로 사용하던 기존 계측 도구를 Elastic APM으로 간단하게 교체할 수 있습니다.

    Jaeger의 원래 계측 도구:

    import io.opentracing.Scope;
    import io.opentracing.Tracer;
    import io.jaegertracing.Configuration;
    import io.jaegertracing.internal.JaegerTracer;
    ...
    private void sayHello(String helloTo) {
        Configuration config = ...
        Tracer tracer = config.getTracer();
        try (Scope scope = tracer.buildSpan("say-hello").startActive(true)) {
            scope.span().setTag("hello-to", helloTo);
        }
        ...
    }
        
    Jaeger를 Elastic OpenTracing 브리지로 교체:

    import io.opentracing.Scope;
    import io.opentracing.Tracer;
    import co.elastic.apm.opentracing.ElasticApmTracer;
    ...
    private void sayHello(String helloTo) {
        Tracer tracer = new ElasticApmTracer();
        try (Scope scope = tracer.buildSpan("say-hello").startActive(true)) {
            scope.span().setTag("hello-to", helloTo);
        }
        ...
    }
        


    다른 추적 코드를 수정할 필요 없이 이렇게 간단한 변경으로 추적 데이터가 Elastic APM으로 원활하게 유입됩니다. 이것이 OpenTracing의 힘입니다!

Elastic APM 실제 사용자 모니터링

추적 및 컨텍스트 전파 등에 대해 설명할 때 대부분 백엔드 서비스에 초점을 맞추고 있지만, 브라우저의 클라이언트 측에서 추적을 시작하는 것도 큰 가치가 있습니다. 이렇게 하면 사용자가 브라우저에서 무언가를 클릭하는 순간 추적 정보를 얻을 수 있습니다. 이 추적 정보는 성능 측면에서 애플리케이션의 ‘실제 사용자 경험’을 나타냅니다. 안타깝게도 현재 해당 정보를 전달할 수 있는 표준화된 방법이 없습니다. W3C 그룹은 앞으로 추적 컨텍스트를 브라우저까지 확장하려고 합니다.

Elastic APM 실제 사용자 모니터링(RUM)은 바로 그 기능을 현재 제공하고 있습니다. RUM JS 에이전트는 클라우드 측 애플리케이션 내에서 실제 사용자 경험을 모니터링합니다. ‘첫 번째 바이트까지 걸리는 시간’, domInteractive 및 domComplete와 같은 메트릭을 측정할 수 있으므로 클라이언트 측 애플리케이션 내 성능 문제는 물론 서버 측 애플리케이션의 지연 시간과 관련된 문제를 찾을 수 있습니다. RUM JS 에이전트는 프레임워크의 구애를 받지 않습니다. 즉, 모든 JavaScript 기반 프론트엔드 애플리케이션에서 사용할 수 있습니다.

<p?</p?

요약

이 블로그가 분산 추적 환경을 더 잘 이해하고 현재 OpenTracing 상황에 대해 혼동이 되었던 부분을 명확히 하는 데 도움이 되었길 바랍니다. 간단한 요약으로 마무리하도록 하겠습니다.

  1. 분산 추적은 마이크로서비스에 대한 귀중한 성능 통찰력을 제공합니다.
  2. OpenTracing은 분산 추적 표준화를 향해 업계에서 내디딘 첫걸음입니다. 완전한 호환성을 위해서는 아직 갈 길이 멉니다.
  3. Elastic APM은 OpenTracing과 호환됩니다.
  4. Elastic OpenTracing 브리지를 사용하면 계측 도구를 재사용할 수 있습니다.
  5. Elastic Stack은 현재 런타임 호환성을 제공하지 않지만, Zipkin 및 Jaeger와 같은 다른 추적 솔루션을 위한 확장성이 뛰어난 장기 스토리지입니다.
  6. Elastic에서는 Elastic 여부와 관계없이 추적 데이터를 위한 풍부한 분석 기능을 제공합니다. 간단한 구성을 통해 Zipkin 또는 Jaeger 추적 데이터를 Elasticsearch로 전송할 수 있습니다.
  7. Elastic APM 실제 사용자 모니터링(RUM)은 클라우드 측 애플리케이션 내 실제 사용자 경험을 모니터링합니다.
  8. 결론적으로 Elastic은 로깅, 메트릭 및 추적이라는 가관측성의 3가지 기둥을 위한 고도로 확장 가능하고 기능이 풍부하며 통합된 분석 플랫폼입니다.

언제나처럼 토론을 시작하거나 궁금한 점이 있으시면 Elastic APM 포럼에 문의하시기 바랍니다. 즐거운 추적 환경을 느껴보시길 바랍니다!