"내 코드는 분명 잘 돌아가는데, 왜 전체 서비스는 느릴까?" "A 서비스에서 B 서비스 호출할 때 어떤 파라미터가 넘어갔더라?"
마이크로서비스 아키텍처(MSA)가 복잡해질수록, 장애의 원인을 찾거나 성능 병목을 분석하는 것은 점점 더 어려워집니다. 마치 거대한 미로 속에서 길을 잃은 기분이죠. 😭
이런 '관측 가능성(Observability)'의 위기 속에서, OpenTelemetry (줄여서 Otel)는 우리에게 구원의 동아줄이 되어줍니다. 오늘은 MSA 지옥에서 길을 잃은 개발자들을 위해 OpenTelemetry의 모든 것을 A to Z로 파헤쳐 보겠습니다!

🤔 그래서 OpenTelemetry가 정확히 뭔가요?
OpenTelemetry는 관측 가능성 데이터를 생성하고 수집하는 방법을 표준화한 오픈소스 프레임워크입니다. 과거에는 각 벤더(Datadog, New Relic 등)나 기술(Jaeger, Prometheus)마다 데이터를 수집하는 방식이 제각각이었죠. Otel은 이 모든 것을 하나로 통일하여, 어떤 시스템을 사용하든 동일한 방식으로 데이터를 수집하고 전송할 수 있게 해주는 '표준 규격'이라고 생각하면 쉽습니다.
전체적인 흐름은 이렇습니다.
애플리케이션 (데이터 생성) ➡️ OpenTelemetry Collector (중간 처리) ➡️ 관측 가능성 백엔드 (Jaeger, Prometheus 등)
이 구조 덕분에 우리는 애플리케이션 코드를 거의 수정하지 않고도 데이터를 보내는 목적지를 자유롭게 바꿀 수 있는 유연성을 얻게 됩니다. ✨
1️⃣ OpenTelemetry의 3대 핵심 데이터: 신호 (Signals)
Otel은 시스템을 관찰하기 위해 세 가지 핵심 데이터, 즉 '신호'를 수집합니다.
🗺️ 트레이스 (Traces): 요청의 전체 여정 추적하기
사용자 요청이 시스템에 들어와서 나갈 때까지, 모든 서비스와 컴포넌트를 거치는 과정을 하나의 여정으로 묶어 보여줍니다. 마치 택배가 어디쯤 오고 있는지 배송 조회를 하는 것과 같아요.
- Trace: 하나의 요청에 대한 전체 여정. (예: 상품 주문 요청 전체)
- Span: 여정 속 하나의 작업 단위. (예: 로그인 확인, 재고 확인, 결제 API 호출)
Span의 구조 (예시)
{ "name": "HTTP GET /api/products", "trace_id": "0af7651916cd43dd8448eb211c80319c", "span_id": "b7ad6b7169203331", "parent_span_id": "f3a4a75a9d201b5a", "start_time": "2025-11-09T11:41:00.123Z", "end_time": "2025-11-09T11:41:00.345Z", "attributes": { "http.method": "GET", "http.status_code": 200, "user.id": "user123" }, "events": [ { "name": "Cache miss", "timestamp": "2025-11-09T11:41:00.200Z" } ] }
이 trace_id만 있으면, 여러 마이크로서비스에 흩어져 있는 작업(Span)들을 하나로 엮어 요청의 전체 흐름을 한눈에 파악할 수 있습니다.
📊 메트릭 (Metrics): 시스템의 건강 상태 측정하기
특정 시점의 시스템 상태를 숫자로 나타내는 데이터입니다. 자동차의 계기판을 생각하면 쉽습니다.
- Counter: 계속 증가만 하는 값 (예: 총 요청 처리 수, 웹사이트 총 방문자 수)
- UpDownCounter: 증가하거나 감소할 수 있는 값 (예: 현재 활성화된 유저 세션 수)
- Histogram: 값의 분포를 측정 (예: API 요청의 95%는 100ms 안에 처리된다)
- Gauge: 특정 시점의 값 (예: 현재 CPU 사용률, 메모리 사용량)
📝 로그 (Logs): 특정 사건의 상세 기록
우리에게 가장 익숙한 데이터죠. 특정 시점에 발생한 이벤트에 대한 텍스트 기록입니다. Otel 로그의 진정한 힘은 트레이스와의 연동에 있습니다.
Otel 로그의 핵심! 로그에 trace_id와 span_id가 포함됩니다. 덕분에 "이 에러 로그가 어떤 요청(Trace)의 어떤 작업(Span)에서 발생했지?"를 즉시 파악할 수 있습니다. 더 이상 로그 파일만 뒤지며 원인을 추측할 필요가 없죠!
2️⃣ 내 코드에 Otel 심기: API & SDK
그럼 이 데이터들을 어떻게 생성할까요? 바로 API와 SDK를 통해 애플리케이션에 '계측(Instrumentation)' 코드를 추가하는 것입니다.
- API: "어떤 데이터를 수집할지"에 대한 명세서(설계도)입니다.
- SDK: API 명세서를 실제로 구현한 언어별 도구(구현체)입니다.
이 둘이 분리되어 있어, 우리는 API 표준에 맞춰 코드만 작성하면 나중에 SDK 구현체를 바꾸더라도 코드를 수정할 필요가 없습니다.
계측 방법은 크게 두 가지입니다.
- 자동 계측 (Automatic Instrumentation) 🪄: 코드 수정 없이, 에이전트나 라이브러리를 추가하는 것만으로 유명 프레임워크(Spring, Django 등)나 라이브러리(HTTP 클라이언트, DB 드라이버)의 데이터를 자동으로 수집합니다. 가장 먼저 시도해야 할 간편하고 강력한 방법입니다!
- 수동 계측 (Manual Instrumentation) ✍️: "우리 회사만의 중요한 비즈니스 로직"처럼 자동 계측이 잡아내지 못하는 부분을 개발자가 직접 API를 호출하여 데이터를 생성합니다.
3️⃣ 만능 데이터 허브: OpenTelemetry Collector
애플리케이션에서 생성된 데이터를 백엔드로 바로 보내는 건 비효율적이고 위험합니다. 애플리케이션에 부하를 줄 수 있고, 백엔드를 바꾸려면 모든 애플리케이션 코드를 수정해야 하니까요.
이때 등장하는 것이 바로 Otel Collector입니다. Collector는 애플리케이션과 백엔드 사이에서 데이터를 수신, 처리, 내보내는 독립적인 프록시 역할을 합니다.

Collector는 레고 블록처럼 세 부분으로 구성됩니다.
- 수신기 (Receivers) 📥: 다양한 형식(OTLP, Jaeger, Prometheus 등)의 데이터를 받아들입니다.
- 처리기 (Processors) 🛠️: 데이터를 가공합니다. 불필요한 데이터를 필터링하거나, 민감한 정보를 마스킹하고, 데이터를 묶어서 효율적으로 처리(Batch)하는 등의 작업을 합니다.
- 내보내기 (Exporters) 📤: 처리된 데이터를 최종 목적지(Jaeger, Prometheus, Datadog 등)로 내보냅니다.
💡 왜 Collector를 써야 할까요?
- 관심사 분리: 애플리케이션은 데이터 '생성'에만 집중하고, Collector가 '처리 및 전송'을 책임져서 앱의 부담을 줄여줍니다.
- 유연성: 데이터를 Jaeger와 Prometheus로 동시에 보내고 싶다면? Collector 설정 파일 한 줄만 바꾸면 끝! 앱 코드는 건드릴 필요가 없습니다.
- 성능: Batch Processor를 사용하면 데이터를 모아서 한 번에 보내므로 네트워크 효율이 극대화됩니다. 프로덕션 환경에서는 SimpleSpanProcessor (스팬이 생길 때마다 즉시 전송) 대신 BatchSpanProcessor 사용이 강력히 권장되는 이유입니다.
Collector 설정 파일 예시 (config.yaml)
Collector가 어떻게 동작하는지는 이 설정 파일 하나로 모두 설명됩니다.
# config.yaml for OpenTelemetry Collector
receivers: # 데이터는 OTLP 프로토콜로 받는다
otlp:
protocols:
grpc:
http:
processors: # 받은 데이터는 일괄 처리하고, 메모리 사용량을 제한한다
batch:
memory_limiter:
check_interval: 1s
limit_percentage: 75
exporters: # 처리된 데이터는 Jaeger로 보내고, 디버깅을 위해 콘솔에도 출력한다
otlp/jaeger:
endpoint: "jaeger-all-in-one:4317" # Jaeger 주소
tls:
insecure: true
logging:
loglevel: debug
service:
pipelines: # 위 컴포넌트들을 파이프라인으로 연결한다
traces: # 트레이스 데이터는 이렇게 처리할거야
receivers: [otlp]
processors: [batch, memory_limiter]
exporters: [otlp/jaeger, logging]
4️⃣ 분산 시스템의 혈관: OTLP & Context Propagation
마지막으로, 이 모든 컴포넌트들이 어떻게 서로 대화하는지 알아봅시다.
- OTLP (OpenTelemetry Protocol) 📡: Otel의 공식 데이터 전송 프로토콜입니다. 모든 Otel 컴포넌트가 알아들을 수 있는 '공용어' 역할을 합니다.
- Context Propagation 🤝: 분산 추적의 핵심 기술입니다. A 서비스에서 B 서비스로 HTTP 요청을 보낼 때, 보이지 않는 곳에서 마법 같은 일이 일어납니다. 바로 traceparent 라는 HTTP 헤더에 trace_id와 같은 추적 정보를 실어 보내는 것이죠.
HTTP 헤더 예시
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
이 헤더 덕분에 B 서비스는 "아, 이 요청은 0af... 트레이스의 일부구나!"라고 인지하고, 자신의 작업(Span)을 같은 트레이스에 연결할 수 있습니다. 이 '문맥 전파'가 없다면 분산 추적은 불가능합니다.
마치며
OpenTelemetry는 단순히 또 하나의 라이브러리나 도구가 아닙니다. 복잡한 현대 분산 시스템의 내부를 투명하게 들여다볼 수 있게 해주는 표준이자 철학입니다.
Otel을 통해 우리는 흩어진 서비스들의 데이터를 하나로 엮어 전체적인 그림을 볼 수 있고, 문제가 발생했을 때 신속하게 원인을 파악하여 해결할 수 있습니다. 더 이상 미로 속에서 헤매지 마세요. OpenTelemetry와 함께 여러분의 시스템에 밝은 등대를 세워보시는 건 어떨까요? 🚀
'클라우드 > opentelemetry' 카테고리의 다른 글
| OpenTelemetry Collector, 아직도 run만 쓰세요? 고수들이 쓰는 5가지 필수 명령어 🚀 (1) | 2025.11.10 |
|---|---|
| 🚨당신이 몰랐던 OpenTelemetry 메트릭의 4단계 비밀 (0) | 2025.11.09 |
| 당신의 서버 로그, 개인정보 유출의 시한폭탄일 수 있습니다 💣 | OpenTelemetry 민감정보 안전하게 처리하는 법 (0) | 2025.11.08 |
| 🤯 "서버 터졌대!" 하이브리드 환경, 모니터링 때문에 머리 아프셨죠? 정답 알려드립니다 (0) | 2025.11.06 |
| 코드 수정 없이 실시간으로 모니터링 설정을 바꾸는 마법? 🧙♂️ (0) | 2025.11.05 |