본문으로 건너뛰기
yutils

observability 는 어떻게 동작할까?

3 기둥 (logs · metrics · traces), 각각의 강점, cardinality 가 cost ceiling 인 이유, 왜 '다 로그하기' 가 안 되나, observability 와 monitoring 의 차이.

약 9분 읽기

production 에서 무언가 잘못 됐다. 그런데 무엇이? 한 사용자만? 모두? DB? 외부 API? — 이 질문에 답하는 능력이 observability. 단순 monitoring (정해진 metric 만 보기) 과 달리, 사전에 정의 안 된 질문에도 답할 수 있어야 한다. 이 가이드는 3 pillars (logs · metrics · traces) 와 cardinality 의 본질을 정리한다.

Monitoring vs Observability — 의미 차이

Monitoring: 알려진 질문에 답
  - CPU > 80% 이면 alert
  - 5xx rate > 1% 이면 alert
  - 미리 정해진 dashboard

Observability: 새 질문에 답할 수 있는 능력
  - "왜 어제 11pm 의 latency 가 튀었나?"
  - "이 user 의 요청이 어디서 실패했나?"
  - "기능 X 출시 후 어느 endpoint 의 p99 가 변했나?"

→ 둘 다 필요. Monitoring 은 "사고 인지", Observability 는 "사고 진단".

3 Pillars — Logs · Metrics · Traces

Logs — 무슨 일이 일어났는지의 기록

형식: 이벤트 (시점 + 컨텍스트)

{
  "ts": "2026-05-25T14:32:01Z",
  "level": "error",
  "msg": "DB connection refused",
  "host": "api-prod-3",
  "user_id": "u_42",
  "request_id": "req_abc123",
  "stack": "..."
}

강점: rich context, 디버깅 정밀
약점: 부피 ↑↑ (TB 단위), 집계 비쌈, 분석 비용

Metrics — 시간 시리즈의 숫자

형식: 시점 + 숫자 + label (집계 가능)

http_requests_total{method="POST", path="/login", status="200"} 1234
http_requests_total{method="POST", path="/login", status="500"} 5

강점: 작음 (이벤트당 ~bytes), 빠른 집계 (count/avg/p99), 대시보드 적합
약점: 사전 정의된 metric 만 가능, 개별 이벤트 detail X

Traces — 요청의 여정

형식: span 들의 tree (시간 + 부모-자식)

trace abc123 (total 450ms)
├─ HTTP POST /login         (450ms)  service: api
│  ├─ DB query users        (320ms)  service: db
│  │  └─ INDEX scan         (310ms)  ← bottleneck!
│  └─ Redis SET session     (15ms)   service: cache

강점: 서비스 간 흐름 명확, 어디서 느린지 한눈에
약점: instrumentation 필요, 부피 ↑ (보통 sampling)

Cardinality — observability cost 의 ceiling

cardinality = label 의 unique 값 조합 수

example 1 — 적음:
  http_requests{method="GET|POST|...", status="200|400|500"}
  → method 5 × status 6 = 30 series

example 2 — 폭발:
  http_requests{method, status, user_id, request_id}
  → user 100 만 × request 1억 = 10^11 series 😱

Prometheus 같은 시스템: cardinality × time series 가 storage cost
DataDog / Honeycomb 등 클라우드: cardinality 별 과금

→ "다 로그하기" 가 안 되는 이유 = cardinality 한도.
   request_id 같은 high-cardinality 는 trace 또는 log 에 두고,
   metric label 에는 두지 마라.

각 pillar 의 적합 use case

질문도구
지금 시스템 건강한가?metrics (dashboard, alert)
이 endpoint 의 p99 추세?metrics
이 요청이 왜 느렸나?traces (해당 trace ID lookup)
이 user 의 에러 원인?logs (user_id filter) + trace
어제 11pm 에 무슨 일?logs (시간 + 컨텍스트 검색)
service A → B 의 latency 분포?traces 집계 + metrics

OpenTelemetry — 단일 표준

이전: 도구마다 다른 SDK
  - DataDog SDK / New Relic agent / Honeycomb SDK / ...
  - 도구 바꾸려면 모든 application 코드 변경

OpenTelemetry (CNCF, 2019+):
  - logs / metrics / traces 의 통일된 spec + SDK
  - exporter 만 바꾸면 backend (Jaeger / Tempo / DataDog / ...) 교체

→ vendor lock-in 해소. instrumentation 한 번, 출력처 자유.

흔한 함정

  • "다 로그하면 된다" — 부피 폭발 + 비용 폭발 + 신호 vs 노이즈. 의도적 sampling + structured.
  • average 만 보고 fine 이라 판단 — average 가 OK 인데 p99 가 2초면 1% 사용자 고통. histogram + percentile 필수.
  • metric label 에 user_id / request_id 박기 — cardinality 폭발. 그것들은 trace / log 에 두기.
  • alert 너무 많음 — 새벽 3시 page 잡음 → on-call burnout. SLO 기반 alert (SLI/SLO 가이드 참조).
  • trace 가 production 영향 — sampling 안 하면 매 요청에 ms overhead. head sampling (1%) 또는 tail sampling (errors 100%).

마무리

Observability 는 단일 도구가 아니라 능력 — 사전에 정의 안 된 질문에 답할 수 있는 능력. 3 pillars 가 보완 (logs = 상세, metrics = 집계, traces = 흐름). cardinality 가 비용 ceiling.

시작: structured logging + 기본 metrics (RED / USE) + 핵심 path 의 tracing. 모든 service 에 full instrumentation 보다 incremental.

가이드 목록으로