본문 바로가기
클라우드/opentelemetry

OpenTelemetry Collector, 여러 백엔드로 데이터를 똑똑하게 분산하는 방법 ⚖️

by gasbugs 2025. 10. 14.

안녕하세요! Observability(관측 가능성) 환경을 구축하다 보면 늘어나는 트래픽을 감당하기 위해 여러 대의 백엔드 인스턴스를 운영하는 경우가 많습니다. OpenTelemetry Collector를 통해 수집된 수많은 트레이스, 메트릭, 로그 데이터를 이 백엔드 인스턴스들에게 어떻게 하면 공평하고 효율적으로 나눠줄 수 있을까요? 🤔

 

오늘은 여러 백엔드에 데이터를 안정적으로 분산시키는 가장 좋은 방법에 대해 알아보겠습니다.

 


🧐 혹시 OTLP Exporter에 엔드포인트를 여러 개 설정하면 되지 않나요?

가장 먼저 떠올릴 수 있는 간단한 방법입니다. OTLP(OpenTelemetry Protocol) 익스포터 설정에 엔드포인트 목록을 추가하는 것이죠.

exporters:
  otlp:
    endpoint: backend-1:4317, backend-2:4317

 

하지만 이 방법은 우리가 원하는 로드 밸런싱(Load Balancing)과는 조금 다릅니다. OTLP 익스포터에 여러 엔드포인트를 설정하는 것은 주로 장애 조치(Failover)를 위해 사용됩니다. 🔄 즉, 첫 번째 엔드포인트에 문제가 생기면 다음 엔드포인트로 보내는 방식이라 데이터가 한쪽으로 쏠릴 수 있습니다. 정교하게 부하를 분산하는 기능이라고 보기는 어렵습니다.


🚀 정답은 바로! Load Balancing Exporter 입니다.

이름에서부터 알 수 있듯이, 이 익스포터는 여러 백엔드 인스턴스에 걸쳐 데이터를 분산(Load Balancing)하는 목적을 위해 특별히 설계되었습니다.

Load Balancing Exporter (loadbalancing)는 내부적으로 OTLP 익스포터를 사용하며, 들어온 데이터를 여러 백엔드에 효과적으로 분배하는 역할을 합니다.

 

주요 특징:

  • 다양한 분배 모드 지원:
    • 라운드 로빈 (Round Robin): 들어오는 요청을 순서대로 각 백엔드에 공평하게 분배합니다. ⚖️
    • 일관된 해싱 (Consistent Hashing): 트레이스 ID를 기반으로 해싱하여, 항상 동일한 트레이스 ID를 가진 스팬(span)들이 같은 백엔드로 가도록 보장합니다. 이는 특정 트레이스 전체를 한 곳에서 분석할 때 매우 유용합니다. 🔗
  • 백엔드 상태 확인: 주기적으로 백엔드의 상태를 확인하고, 문제가 있는 백엔드는 분배 대상에서 제외하여 안정성을 높입니다.

이처럼 loadbalancing 익스포터는 데이터를 여러 백엔드에 균등하게, 그리고 의도한 방식대로 분배하는 데 가장 최적화된 선택입니다.


⚠️ 잠깐, 이 컴포넌트들과 헷갈리지 마세요!

OpenTelemetry Collector에는 다양한 컴포넌트가 있어 역할이 헷갈릴 수 있습니다. 데이터 분산과 관련하여 자주 혼동되는 두 가지 프로세서(Processor)를 살펴보겠습니다. (이들은 익스포터가 아닙니다!)

1. Queued Retry Processor

이 컴포넌트는 이름처럼 재시도(Retry)와 큐(Queue)를 관리하는 역할을 합니다. 💪

  • 역할: 익스포터가 데이터를 백엔드로 전송하는 데 실패했을 경우, 바로 버리는 것이 아니라 잠시 큐에 저장했다가 다시 보내는 역할을 합니다.
  • 목적: 일시적인 네트워크 문제 등으로 인한 데이터 유실을 막고 전송 신뢰성을 높이는 것이 주 목적입니다. 데이터 분산과는 직접적인 관련이 없습니다.

2. Routing Processor (routing)

이 컴포넌트는 들어온 데이터의 속성(attribute)을 보고 어디로 보낼지 결정하는 교통 경찰 🚦 역할을 합니다.

  • 역할: 데이터에 포함된 특정 속성(예: 서비스 이름, 환경 정보 등)을 기준으로 "이 데이터는 A 파이프라인으로 보내", "저 데이터는 B 파이프라인으로 보내" 와 같이 조건부 라우팅을 수행합니다.
  • 목적: 모든 데이터를 균등하게 나누는 것이 아니라, 데이터의 내용에 따라 의도적으로 다른 목적지로 보내는 것이 주 목적입니다.

🏗️ 아키텍처 구성도

OpenTelemetry(Otel) 환경에서 Load Balancing Exporter를 적용하는 예제를 보여드리겠습니다.

 

정확히 말하면, 'Load Balancing Exporter'라는 이름의 단일 컴포넌트가 있는 것은 아닙니다. 일반적인 아키텍처는 여러 개의 OTel Collector(수집기) 인스턴스를 실행하고, 그 앞에 로드 밸런서를 두는 방식입니다. 애플리케이션의 Otel Exporter는 이 로드 밸런서의 주소만 바라보게 설정합니다.

 

이 구조는 다음과 같은 큰 장점이 있습니다.

  • 고가용성 (High Availability): 여러 Collector 중 하나에 장애가 발생해도 중단 없이 텔레메트리 데이터를 수집할 수 있습니다.
  • 확장성 (Scalability): 데이터 양이 늘어나면 Collector 인스턴스만 추가하여 쉽게 확장할 수 있습니다.

 

개념을 먼저 이해하면 코드를 파악하기 쉽습니다.

[App 1] ---►                                 ---► [Collector 1]
[App 2] ---► [Load Balancer] (단일 Endpoint) ---► [Collector 2]
[App 3] ---►                                 ---► [Collector 3]

 

 

모든 App은 단일 Endpoint인 LoadBalancer로 보내면 LB가 스스로 Collector1부터 3까지 분산해줍니다. 

 

애플리케이션(App)의 Exporter는 로드 밸런서의 주소(http://otel-collector-lb:4317) 하나만 알고 있으면 됩니다. 트래픽을 여러 Collector로 분산하는 역할은 로드 밸런서가 담당합니다.


🐍 파이썬(Python) 적용 예제

가장 일반적인 OTLP Exporter를 사용하여 로드 밸런서 뒤에 있는 Collector로 데이터를 보내는 파이썬 코드 예제입니다.

1. 필요한 라이브러리 설치

pip install opentelemetry-api \
            opentelemetry-sdk \
            opentelemetry-exporter-otlp-proto-grpc

2. Exporter 설정 및 데이터 전송 코드

애플리케이션 코드에서는 Exporter의 엔드포인트(endpoint)를 로드 밸런서의 주소로 지정하는 것이 핵심입니다.

import time
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource

# OTLP Exporter를 gRPC 프로토콜로 가져옵니다.
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# ----------------------------------------------------
# 1. 핵심 설정: Exporter의 엔드포인트를 로드 밸런서 주소로 지정
# ----------------------------------------------------
# 실제 환경에서는 Kubernetes 서비스 주소나 클라우드 로드 밸런서의 DNS 주소를 사용합니다.
# gRPC 기본 포트는 4317, HTTP는 4318입니다.
LOAD_BALANCER_ENDPOINT = "otel-collector-lb:4317"

# 서비스 이름 등 리소스를 정의합니다.
resource = Resource(attributes={
    "service.name": "my-python-app"
})

# TracerProvider를 설정합니다.
provider = TracerProvider(resource=resource)

# OTLPSpanExporter 인스턴스를 생성하며 endpoint를 지정합니다.
otlp_exporter = OTLPSpanExporter(endpoint=LOAD_BALANCER_ENDPOINT, insecure=True) # insecure=True는 로컬 테스트용

# 스팬을 배치 처리할 BatchSpanProcessor를 설정합니다.
processor = BatchSpanProcessor(otlp_exporter)
provider.add_span_processor(processor)

# OpenTelemetry의 기본 TracerProvider로 설정합니다.
trace.set_tracer_provider(provider)

# 애플리케이션의 트레이서를 가져옵니다.
tracer = trace.get_tracer(__name__)


# ----------------------------------------------------
# 2. 실제 데이터(Span) 생성 및 전송
# ----------------------------------------------------
def do_work():
    """예제 작업을 수행하고 스팬을 생성하는 함수"""
    with tracer.start_as_current_span("do_work") as span:
        print("작업을 수행 중입니다...")
        time.sleep(1)
        span.set_attribute("job.status", "completed")
        print("작업 완료!")

if __name__ == "__main__":
    do_work()
    
    # 실제 애플리케이션에서는 이 부분이 필요 없지만,
    # 예제에서는 스팬이 전송될 시간을 확보하기 위해 추가합니다.
    time.sleep(2) 
    print("텔레메트리 데이터 전송 완료.")

핵심 포인트

위 코드에서 OTLPSpanExporter(endpoint="otel-collector-lb:4317", ...) 부분이 가장 중요합니다.

애플리케이션은 텔레메트리 데이터를 어디로 보낼지 단 하나의 주소만 알면 되므로, 코드가 매우 단순해집니다. 백엔드의 Collector가 몇 대로 늘어나든 애플리케이션 코드는 수정할 필요가 없습니다.


⚙️ OTel Collector 설정 예제

참고로, 로드 밸런서 뒤에서 실행될 각 Collector들의 설정 파일(otel-collector-config.yaml)은 매우 간단하며 일반적으로 동일한 구성을 가집니다.

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        # 로드 밸런서로부터 gRPC 트래픽을 받을 포트 (기본값: 4317)
        endpoint: 0.0.0.0:4317
      http:
        # 로드 밸런서로부터 HTTP 트래픽을 받을 포트 (기본값: 4318)
        endpoint: 0.0.0.0:4318

exporters:
  # 수집한 데이터를 Jaeger, Prometheus, 클라우드 모니터링 서비스 등으로 보냅니다.
  logging: # 간단히 콘솔에 로그로 출력하는 Exporter
    loglevel: debug

processors:
  batch:

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging] # 실제로는 Jaeger, Tempo, AWS X-Ray 등으로 설정

 

이처럼 Otel에서 로드 밸런싱을 구현하는 것은 특정 Exporter를 사용하는 것이 아니라, 표준 아키텍처 패턴을 적용하는 것에 가깝습니다.

 


✨ 결론

OpenTelemetry Collector에서 수집한 데이터를 여러 백엔드 인스턴스로 균등하게 분산하여 부하를 나누고 싶다면, 고민 없이 Load Balancing Exporter (loadbalancing)를 사용하세요! 이것이 바로 그 목적을 위해 탄생한 가장 확실하고 강력한 방법입니다.