관측성(로그·지표·추적)
운영 중인 시스템 안에서 무슨 일이 일어나는지 밖으로 나온 신호만으로 알아내는 능력, 곧 관측성을 정리한다. 로그·지표·추적·프로파일의 쓰임새, OpenTelemetry로 계측하고 traceparent로 추적을 잇는 방법, 지표 종류와 RED·USE, SLO와 오류 예산으로 경보를 거는 계산, 카디널리티와 로깅 습관까지 다룬다.
목차 (13)
부하를 일부러 걸어 한계를 재는 방법은 부하 테스트 노트에, 장애에 버티는 구조 설계는 시스템 설계 › 규모 확장에 있다. 관측성은 그 둘이 실제 운영에서 맞는지를 보는 눈이다. 도구 이름은 2026년 10월 기준이다.
모니터링과 관측성
모니터링은 미리 정한 질문 — CPU가 넘쳤나, 오류율이 문턱을 넘었나 — 을 대시보드와 경보로 지켜보는 일이다. 고장 나는 방식을 이미 알 때 잘 맞는다. 마이크로서비스처럼 부품이 많아지면 처음 보는 방식으로 고장 나는 일이 늘어, 미리 만든 대시보드에는 답이 없다. 관측성(observability)은 원래 제어 이론에서 "출력만 보고 내부 상태를 알아낼 수 있는 정도"를 뜻하는 말로, 소프트웨어에서는 코드를 새로 배포하지 않고도 새 질문을 던져 답을 찾을 수 있는 능력을 가리킨다.
새 질문에 답하려면 데이터가 풍부해야 한다. 요청 하나에 사용자 등급·앱 버전·리전·기능 플래그 같은 속성이 붙어 있어야 쪼개 볼 수 있고, 로그·지표·추적이 같은 ID로 이어져 있어야 한 신호에서 다른 신호로 건너간다.
네 가지 신호
관측 데이터는 흔히 세 기둥 — 로그, 지표, 추적 — 으로 나누고, 최근에는 프로파일을 네 번째로 더한다(OpenTelemetry 신호).
- 로그: 사건 하나하나의 기록. 가장 자세하지만 양이 많아 저장·검색 비용이 가장 크다.
- 지표(metrics): 일정 간격으로 모은 수치의 시계열. 작고 싸서 오래 보관하고 경보를 걸기 좋지만, 미리 집계한 만큼만 볼 수 있다.
- 추적(traces): 요청 하나가 여러 서비스를 지나며 각 구간에서 쓴 시간. 분산 시스템에서 "어디가 느린가"에 답한다.
- 프로파일: 코드의 어느 함수가 CPU·메모리를 썼는지를 표본 추출로 늘 모으는 것(지속 프로파일링). OpenTelemetry는 2024년에 이를 네 번째 신호로 넣겠다고 발표했고, 다른 셋보다 늦게 안정화되고 있다.
OpenTelemetry
OpenTelemetry(OTel)는 신호를 만들고 보내는 방법의 공개 표준과 구현이다. 2019년 추적 표준 둘(OpenTracing, OpenCensus)이 합쳐져 CNCF 프로젝트가 됐다. 핵심은 "계측은 한 번, 저장소는 고르기"다. 예전에는 도구를 바꾸면 계측 코드를 다 바꿔야 했다.
- API: 스팬을 열고 지표를 기록하는 인터페이스. 라이브러리는 이것만 부르고, SDK가 없으면 아무 일도 하지 않아 부담이 없다.
- SDK: 샘플링, 일괄 전송, 리소스 속성(
service.name등) 부착을 맡는 구현. 웹 프레임워크·DB 드라이버·HTTP 클라이언트를 자동으로 계측하는 패키지가 많아, 코드 수정 없이 기본 추적이 나온다. - OTLP: 신호를 보내는 프로토콜. gRPC(기본 포트 4317)와 HTTP(4318)로 보낸다(명세). 대부분의 오픈소스·상용 백엔드가 OTLP를 직접 받는다.
- Collector: 받기(receivers)·가공(processors)·내보내기(exporters) 파이프라인을 설정 파일로 짜는 중계기(문서). 민감 속성 지우기, 테일 샘플링, 여러 백엔드로 나눠 보내기를 앱 밖에서 한다. 노드마다 두는 에이전트와 가운데 모으는 게이트웨이를 겹쳐 쓰기도 한다.
분산 추적
추적(trace) 하나는 요청 하나의 전체 경로이고, 그 안의 구간 하나하나가 스팬(span)이다. 스팬은 이름, 시작·끝 시각, 속성, 상태, 그리고 부모 스팬의 ID를 가진다. 이 구조는 구글의 Dapper(2010)에서 왔다. 서비스가 여럿이면 다음 서비스에 "지금 어느 추적의 어느 스팬 안에서 부르는지"를 알려 줘야 하는데, 이것을 문맥 전파라 하고 HTTP에서는 W3C Trace Context의 traceparent 헤더를 쓴다.
gateway가 요청을 받는다. 들어온 traceparent가 없으니 새 trace-id를 만들고 루트 스팬을 연다.
모인 스팬을 시간축에 늘어놓으면 폭포 그림이 된다. 부모 스팬의 막대에서 자식이 덮지 않는 빈 구간은 그 서비스 자신이 쓴 시간이다.
- flags의 sampled 비트: 첫 서비스가 기록하기로 정하면 01을 실어 보내고, 뒤 서비스들은 이를 따라(부모 기반 샘플링) 추적이 중간에 끊기지 않는다.
- 큐를 건너는 추적: 메시지 큐에서는 메시지 헤더에 문맥을 싣는다. 소비가 한참 뒤에 일어나면 부모-자식 대신 스팬 링크(link)로 잇는다.
- tracestate: 벤더별 추가 정보를 싣는 두 번째 헤더. 몰라도 그대로 전달만 하면 된다.
지표 종류
Prometheus와 OTel이 쓰는 지표 종류는 거의 같다. 종류를 잘못 고르면 집계가 틀어진다.
- 카운터: 늘기만 하는 누적값(요청 수, 오류 수). 값 자체보다 초당 증가율(
rate())을 본다. 프로세스가 재시작하면 0으로 돌아가는데, rate 계산이 이를 알아서 보정한다. - 게이지: 오르내리는 현재값(메모리 사용량, 큐 길이, 연결 수). 여러 인스턴스의 값을 더하거나 평균 낼 수 있다.
- 히스토그램: 값을 버킷별로 센다. 인스턴스 여러 대의 버킷을 더한 뒤 분위수를 구할 수 있다는 것이 핵심이다. 반면 인스턴스마다 미리 계산한 p99(서머리)는 평균을 내면 의미 없는 숫자가 된다. 예의 버킷에서 p99는 1.58초로 어림되는데, 실제 값은 1초~2.5초 버킷 안 어디든 될 수 있다(히스토그램 실무). 버킷을 자동으로 잘게 나누는 지수(native) 히스토그램이 이 오차를 줄인다.
RED와 USE
무엇을 지표로 둘지 정하는 두 가지 점검표가 있다. 서비스에는 RED(Rate·Errors·Duration), 자원에는 USE(Utilization·Saturation·Errors)다.
- 구글 SRE 책의 네 가지 황금 신호(지연·트래픽·오류·포화도)는 RED에 포화도를 더한 것과 같다.
- 포화도는 사용률보다 먼저 문제를 알린다. CPU 사용률 70%라도 실행 대기열이 길면 이미 요청이 기다리고 있다.
- 지연은 평균이 아니라 분포(p50·p99)로 본다. 평균은 소수의 아주 느린 요청을 가린다. 그리고 실패한 요청의 지연은 따로 본다. 빨리 실패하는 오류가 평균 지연을 좋아 보이게 만든다.
SLI·SLO·오류 예산
SLI(service level indicator)는 사용자 경험을 나타내는 측정값으로, 보통 "좋은 이벤트 ÷ 전체 이벤트"(예: 300ms 안에 성공한 요청의 비율)로 정한다. SLO(objective)는 그 목표치(30일 동안 99.9%), SLA(agreement)는 어겼을 때 보상이 따르는 계약이다(SRE 책). SLO가 100%가 아닌 이유는 남는 몫, 곧 오류 예산을 배포·실험에 쓰기 위해서다.
- 99.9%·30일의 예산은 시간으로 43.2분, 요청으로는 한 달 10,000,000건 중 10,000건이다. 99.95%면 21.6분, 99%면 7.2시간이다. 9를 하나 늘릴 때마다 예산이 10분의 1이 된다.
- 소진율(burn rate) = 실제 오류율 ÷ (1 − SLO). 오류율이 0.5%로 이어지면 소진율 5, 곧 6일 만에 한 달 예산이 바닥난다.
- 예산이 남으면 배포를 서두르고, 바닥나면 기능 배포를 멈추고 안정성에 집중한다는 규칙을 팀이 미리 합의해 두는 것이 SLO의 쓸모다(SRE 워크북).
경보: 다중 창 소진율
"오류율 1% 넘으면 경보" 같은 고정 문턱은 짧은 튐에 밤잠을 깨우거나, 낮은 오류가 오래 이어져 예산을 다 먹는 것을 놓친다. SRE 워크북은 몇 가지 방식을 견준 끝에 예산을 얼마나 빨리 쓰는가로 경보를 거는 다중 창·다중 소진율 방식을 권한다.
- 첫 규칙의 문턱은 0.02 × 720시간 ÷ 1시간 = 14.4이고, 99.9%에서는 오류율 1.44%다. 이 속도가 이어지면 50시간 만에 예산이 바닥나므로 사람을 깨운다(page). 느린 소진은 티켓으로 근무 시간에 본다.
- 짧은 창(긴 창의 1/12)을 함께 보는 이유는 복구가 빠르게 반영되게 하기 위해서다. 장애가 끝났는데도 1시간 창의 평균이 높아 계속 울리는 일을 막는다.
- 경보는 원인(CPU, 디스크)이 아니라 증상(사용자가 겪는 SLO 위반)에 건다. 원인 지표는 대시보드에 두고 진단에 쓴다. 울린 경보마다 사람이 할 일이 있어야 하며, 할 일이 없는 경보는 지운다.
카디널리티
지표 저장소는 지표 이름과 레이블 값의 조합 하나하나를 별도 시계열로 저장한다. 그래서 시계열 수는 레이블 값 가짓수의 곱이다. 이 수를 카디널리티라 하며, 지표 비용과 장애의 가장 흔한 원인이다(Prometheus 이름 짓기 지침).
- 경로 레이블에는
/users/8812같은 원문 대신/users/:id같은 라우트 틀을 넣는다. - 사용자·주문 ID처럼 끝없는 값은 추적의 속성이나 구조화 로그의 필드로 둔다. 추적·로그 저장소는 이런 높은 카디널리티를 다루도록 만들어졌다. 관측성 도구들이 "넓은 이벤트"(속성이 많이 붙은 이벤트)를 강조하는 것도 이 때문이다.
- 배포 후 시계열 수를 지표로 지켜보고, 새 레이블은 값의 가짓수를 먼저 어림한다.
APM 제품
APM(application performance monitoring)은 추적·지표·로그를 한 화면에서 잇는 제품군을 부르는 이름이다. 도구는 계측·수집·저장 세 층으로 나눠 보면 고르기 쉽다. 아래 이름은 대표적인 것을 순서 없이 늘어놓은 것이며 추천이 아니다.
- 오픈소스 직접 운영: 지표는 Prometheus(장기 보관은 Mimir·Thanos 같은 확장), 추적은 Jaeger·Tempo, 로그는 Loki·OpenSearch, 화면은 Grafana가 흔한 조합이다. 라이선스 비용이 없는 대신 저장소 운영이 일이 된다.
- 상용·관리형: 설치가 쉽고 신호 연결·이상 탐지 같은 기능이 붙어 있지만, 보통 데이터양·호스트 수에 비례해 과금돼 규모가 커지면 비용이 가파르게 오른다. 클라우드 사업자의 자체 도구는 그 클라우드 자원과 붙이기 쉽다.
- 어느 쪽이든 고를 때는 OTLP를 그대로 받는지, 데이터 보관 기간과 단가, 높은 카디널리티 질의를 얼마나 빠르게 하는지, 데이터를 다른 곳으로 꺼낼 수 있는지를 본다.
로깅 습관
로그는 사람이 읽을 문장이 아니라 기계가 거를 이벤트로 남긴다. 필드 이름을 OTel의 로그 데이터 모델·시맨틱 규칙에 맞추면 도구를 바꿔도 질의가 그대로 통한다.
- trace_id를 넣는다: 로그 한 줄에서 그 요청의 추적 전체로 건너갈 수 있다. OTel 로그 연동을 쓰면 현재 스팬의 ID가 자동으로 붙는다.
- 심각도를 지킨다: ERROR는 사람이 볼 일, WARN은 스스로 회복한 이상, INFO는 상태 변화, DEBUG는 평소에 끈다. 모든 것이 ERROR면 아무것도 ERROR가 아니다.
- 민감 정보를 남기지 않는다: 비밀번호·토큰·카드 번호·주민번호를 로그에 쓰지 않는다. 로그는 접근 권한이 넓고 오래 남는다. 남겨야 하면 가리거나(마스킹) Collector에서 지운다.
- 양을 다룬다: 같은 메시지가 초당 수천 번 나오면 표본만 남기고(로그 샘플링) 개수는 지표로 센다. 오래된 로그는 싼 저장소로 옮기고 보관 기간을 정해 지운다.
추적도 모두 남기면 비싸다. 요청이 시작될 때 무작위로 정하는 헤드 샘플링은 싸고 단순하지만 드문 오류 추적까지 같은 비율로 버린다. 요청이 끝난 뒤 추적 전체를 보고 정하는 테일 샘플링은 오류·느린 추적을 모두 남길 수 있는 대신, Collector가 추적이 끝날 때까지 스팬을 메모리에 모아 둬야 한다(샘플링).
예에서 모두 저장하면 하루 86,400,000개, 헤드 1%는 864,000개, 테일은 전체의 2.48%인 2,147,040개다. 샘플링한 추적으로 요청 수를 세면 틀리므로, 개수·비율은 샘플링 전에 지표로 따로 센다.
장애 대응: 온콜, 지휘, 포스트모템
관측성은 경보가 울린 뒤의 대응까지 이어져야 값을 한다. Google SRE 책은 장애 관리의 우선순위를 “피를 멈추고, 서비스를 되살리고, 원인을 찾을 증거를 남긴다” 순서로 적는다(Managing Incidents). 원인을 끝까지 밝히는 것보다 롤백이나 트래픽 우회로 사용자 피해부터 줄이는 것이 먼저이고, 원인 분석은 그다음이다.
- 역할을 나눈다: 큰 장애에서는 전체 상황을 쥐고 일을 나눠 주는 지휘자(incident commander), 실제로 시스템을 고치는 사람, 바깥에 상황을 알리는 사람을 따로 둔다. 지휘자는 누가 무엇을 했는지 적는 실시간 장애 문서를 유지한다.
- 절차는 미리: 대응 절차와 연락 경로는 장애 전에 써 두고 연습한다. 경보마다 무엇을 확인하고 무엇을 할지 적은 런북(runbook)을 경보 설명에 링크해 두면 새벽에 깬 당번도 같은 순서로 움직인다.
- 온콜의 양을 잰다: Google SRE는 SRE 시간의 25% 이하만 온콜에 쓰게 하고, 사건 하나를 처리하고 후속 작업까지 마치는 데 6시간쯤 걸린다고 보아 12시간 당번 한 번에 사건 2건을 상한으로 둔다(Being On-Call). 그보다 자주 울리면 사람을 늘리기 전에 경보와 시스템을 고친다.
- 비난 없는 포스트모템: 장애 뒤에는 무슨 일이 언제 일어났고, 무엇이 피해를 키웠고, 무엇을 고칠지 글로 남긴다. 사람이나 팀을 탓하지 않고 원인이 된 조건에 집중해야 다음에도 사람들이 실수를 숨기지 않고 말한다. 사용자에게 보인 장애, 데이터 손실, 당번의 수동 개입(롤백, 트래픽 우회), 감시가 장애를 못 잡은 경우처럼 써야 하는 기준을 장애 전에 정해 둔다(Postmortem Culture).
핵심 자료
| 자료 | 성격 | 한 줄 요지 |
|---|---|---|
| Dapper, a Large-Scale Distributed Systems Tracing Infrastructure (Sigelman 등) | 논문(2010) | 구글의 분산 추적 시스템. 트레이스·스팬·샘플링이라는 오늘날 추적의 기본 틀이 여기서 나왔다. |
| Site Reliability Engineering — Service Level Objectives | 책(2016) | SLI·SLO·SLA를 구분하고 목표를 어떻게 고르는지 설명한 장. |
| The Site Reliability Workbook — Alerting on SLOs | 책(2018) | 경보 방식 여섯 가지를 비교해 다중 창·다중 소진율 경보에 이르는 과정을 숫자로 보인다. |
| W3C Trace Context | 표준 | traceparent·tracestate 헤더로 추적 문맥을 서비스 사이에 전달하는 형식. |
| OpenTelemetry 문서 | 공식 문서 | API·SDK·Collector·OTLP와 신호별 개념. 계측의 사실상 표준이다. |
| The USE Method (Brendan Gregg) | 글 | 자원마다 사용률·포화도·오류를 차례로 보는 성능 점검 순서. |
- Dapper, a Large-Scale Distributed Systems Tracing Infrastructure (Sigelman 등)
- Site Reliability Engineering — Service Level Objectives
- The Site Reliability Workbook — Alerting on SLOs
- W3C Trace Context
- OpenTelemetry 문서
- The USE Method (Brendan Gregg)
- Site Reliability Engineering — Managing Incidents
- Site Reliability Engineering — Being On-Call
- Site Reliability Engineering — Postmortem Culture
- Site Reliability Engineering — Monitoring Distributed Systems
- The Site Reliability Workbook — Implementing SLOs
- OpenTelemetry — 신호
- OpenTelemetry — Collector
- OTLP 명세
- OpenTelemetry 블로그 — 프로파일링 신호(2024)
- OpenTelemetry — 샘플링
- OpenTelemetry — 로그 데이터 모델
- Prometheus — 지표 종류
- Prometheus — 히스토그램과 서머리
- Prometheus — 지표와 레이블 이름 짓기
- The RED Method (Grafana Labs 블로그)
- Jaeger