모니터링 화면에는 모든 서버가 초록색인데 고객센터에는 “결제가 계속 실패한다”는 문의가 들어옵니다. CPU 사용률은 낮고 메모리도 충분하며 API 평균 응답 시간도 정상입니다. 그런데 특정 국가의 특정 결제수단을 사용하는 고객만 20초 뒤 타임아웃을 경험하고 있다면, 서버 상태만 보는 대시보드로는 문제를 찾기 어렵습니다.
관측 가능성(Observability)은 수집한 신호를 이용해 시스템 내부에서 무슨 일이 일어나는지 외부에서 추론할 수 있는 능력입니다. 정해 둔 장애를 감지하는 모니터링을 넘어, 미리 예상하지 못한 질문에도 데이터를 따라 답할 수 있어야 합니다.
이를 위해 흔히 로그, 메트릭, 트레이스라는 세 가지 신호를 사용합니다. 중요한 것은 도구를 세 개 설치하는 것이 아니라, 사용자의 한 요청이 세 신호 안에서 같은 맥락으로 연결되게 설계하는 것입니다. 이번 글에서는 수집 항목부터 SLO, 알림, 비용과 운영 절차까지 차례대로 살펴보겠습니다.
관측의 출발점은 서버가 아니라 사용자 행동이다
“API 서버가 살아 있는가?”보다 “사용자가 주문을 완료할 수 있는가?”가 더 중요한 질문입니다. 서비스가 여러 API와 큐, 데이터베이스, 외부 결제사를 거친다면 개별 컴포넌트가 모두 정상이어도 전체 사용자 여정은 실패할 수 있습니다.
먼저 회원가입, 검색, 주문, 결제처럼 핵심 사용자 여정을 정의합니다. 각 여정의 성공 조건과 허용 지연을 정하고, 요청이 어느 서비스와 외부 의존성을 지나는지 그립니다. 이 흐름이 있어야 어떤 로그와 메트릭을 남기고 어디에 트레이싱을 연결할지 결정할 수 있습니다.
인프라 지표는 여전히 필요하지만 원인이 아니라 맥락인 경우가 많습니다. CPU 상승은 사용자 지연의 원인일 수도 있고 갑자기 트래픽이 늘어난 결과일 수도 있습니다. 사용자 결과를 먼저 보고 아래 계층으로 내려가야 중요하지 않은 그래프에 시간을 낭비하지 않습니다.
세 가지 신호는 서로 다른 질문에 답한다
로그, 메트릭, 트레이스는 경쟁 관계가 아닙니다. 각각 해상도와 비용, 답할 수 있는 질문이 다릅니다.
- 로그: 특정 사건에서 정확히 무엇이 일어났는지 상세 맥락을 보여줍니다.
- 메트릭: 많은 사건을 집계해 시스템의 추세와 이상을 빠르게 보여줍니다.
- 트레이스: 한 요청이 여러 서비스를 통과한 경로와 각 구간의 시간을 연결합니다.

결제 실패율이 상승했다는 사실은 메트릭이 빠르게 알려줍니다. 어떤 서비스 구간에서 시간이 늘었는지는 트레이스가 보여주고, 외부 결제사가 반환한 오류 코드와 재시도 결과는 로그에서 확인합니다. 세 신호 사이에 trace ID, service name, deployment version 같은 공통 속성이 있어야 클릭 몇 번으로 이동할 수 있습니다.
로그는 문장이 아니라 질의 가능한 사건으로 남긴다
결제 실패라는 한 줄은 사람에게 읽히지만 원인을 집계하기 어렵습니다. 구조화 로그는 timestamp, level, service, event name, order ID, payment provider, result code, duration, trace ID를 JSON 같은 일정한 필드로 기록합니다. 그러면 “새 버전 배포 후 특정 결제사에서 증가한 오류”를 바로 검색할 수 있습니다.
{
"event": "payment.authorize.failed",
"service": "checkout-api",
"provider": "gateway-a",
"result_code": "timeout",
"duration_ms": 10023,
"trace_id": "...",
"deployment": "2026.08.31.3"
}
모든 요청에 INFO 로그를 여러 줄씩 남기는 것은 관측 가능성을 높이지 않습니다. 같은 정보를 반복하면 저장 비용과 검색 잡음만 커집니다. 요청 완료 시 결과와 핵심 속성을 한 사건으로 남기고, 상세 디버그 로그는 필요할 때 일정 시간이나 특정 대상에만 활성화하는 편이 낫습니다.
비밀번호, 액세스 토큰, 카드번호, 주민번호 같은 민감 정보는 절대 로그에 남기지 않아야 합니다. 이메일과 사용자 ID도 목적에 맞게 마스킹하거나 내부 식별자로 대체하고 보존 기간과 접근 권한을 정합니다. 예외 객체와 HTTP 본문을 그대로 출력하는 코드가 비밀값을 우회적으로 기록하지 않는지 점검해야 합니다.
메트릭은 적은 비용으로 전체 흐름을 본다
메트릭은 초당 요청 수, 오류율, 응답 시간 분포처럼 수많은 사건을 집계해 추세를 보여줍니다. Counter는 누적 요청과 오류 수, Gauge는 현재 큐 길이와 활성 연결 수, Histogram은 응답 시간과 메시지 크기의 분포를 표현하는 데 적합합니다.
평균 응답 시간만 보면 일부 사용자의 심한 지연이 가려집니다. p50, p95, p99 같은 분위수와 임계값을 넘긴 요청 비율을 함께 봐야 합니다. 평균 200ms인 API도 1%의 요청이 15초라면 대규모 사용자에게는 중요한 문제입니다.
메트릭 라벨에는 service, route, status class, region처럼 값의 종류가 제한된 속성을 사용합니다. user ID, order ID, 전체 URL, 오류 메시지를 라벨로 넣으면 시계열 수가 폭발하는 고카디널리티 문제가 생깁니다. 세부 식별자는 로그와 트레이스에 두고 메트릭은 집계 가능한 차원으로 제한합니다.
분산 트레이스는 요청의 경로와 대기 시간을 보여준다
마이크로서비스 환경에서 사용자의 요청 하나는 API Gateway, 주문 서비스, 재고 서비스, 메시지 브로커와 결제사를 거칠 수 있습니다. 각 작업 구간을 span으로 기록하고 부모·자식 관계로 묶으면 전체 trace가 됩니다. 어느 서비스가 느린지뿐 아니라 네트워크 대기, DB 쿼리, 재시도가 시간을 얼마나 사용했는지 볼 수 있습니다.
trace context는 HTTP 헤더와 메시지 메타데이터를 통해 다음 서비스로 전달해야 합니다. 비동기 큐에서는 생산 시각과 소비 시각, 메시지 ID와 원래 trace의 연결을 기록합니다. 컨텍스트 전파가 한 구간에서 끊기면 여러 조각의 트레이스로 보이므로 공통 라이브러리와 표준 계측이 중요합니다.
모든 요청의 모든 span을 영구 저장하면 비용이 큽니다. 일반 요청은 일부만 샘플링하되 오류나 매우 느린 요청은 더 높은 비율로 남기는 tail-based sampling을 검토할 수 있습니다. 단, 샘플링 결정 전에는 집계 메트릭이 전체 요청을 반영하도록 분리해야 합니다.
표준 계측과 업무 계측을 함께 사용한다
HTTP 서버, 데이터베이스 드라이버, 메시지 클라이언트는 자동 계측으로 기본 span과 메트릭을 빠르게 수집할 수 있습니다. OpenTelemetry 같은 표준을 사용하면 코드의 계측 방식과 저장·조회 도구를 어느 정도 분리할 수 있습니다.
하지만 자동 계측만으로는 “결제 승인 성공”과 “쿠폰 적용 실패” 같은 업무 의미를 알 수 없습니다. 핵심 유스케이스의 시작과 결과, 외부 의존성, 업무 식별자와 실패 이유를 명시적으로 추가해야 합니다. 기술 span 이름과 업무 이벤트 이름의 규칙을 팀 전체가 공유하면 검색과 대시보드가 일관됩니다.
계측 코드 자체가 서비스 실패를 만들면 안 됩니다. 수집기 연결이 끊겨도 요청 처리는 계속되어야 하고, 전송 큐에는 크기 제한과 폐기 정책이 필요합니다. 관측 데이터 전송 때문에 메모리가 고갈되는 역설을 막아야 합니다.
RED와 USE로 빠르게 질문의 범위를 좁힌다
사용자 요청을 처리하는 서비스에는 RED 방법이 유용합니다. Rate는 요청량, Errors는 실패 비율, Duration은 지연 분포입니다. 세 지표를 서비스와 주요 route별로 보면 트래픽 변화, 오류, 느려짐을 빠르게 구분할 수 있습니다.
CPU, 메모리, 디스크, 네트워크 같은 자원은 USE 관점으로 봅니다. Utilization은 얼마나 사용 중인지, Saturation은 대기열이 쌓이는지, Errors는 하드웨어나 커널 수준 실패가 있는지입니다. CPU가 60%여도 실행 큐가 길거나 스로틀링이 발생하면 포화 상태일 수 있습니다.
장애 조사에서는 사용자 SLI에서 시작해 RED로 어느 서비스가 영향을 주는지 찾고, 해당 서비스의 USE와 트레이스로 내려갑니다. 이 순서를 런북으로 만들면 담당자의 경험에만 의존하지 않고 공통 절차로 대응할 수 있습니다.
SLI와 SLO는 “정상”을 사용자 언어로 정의한다
SLI(Service Level Indicator)는 사용자가 경험하는 품질을 측정하는 지표입니다. 성공한 결제의 비율, 300ms 안에 완료된 검색 비율, 누락 없이 처리된 메시지 비율이 예입니다. SLO(Service Level Objective)는 일정 기간 동안 달성하려는 목표입니다.
예를 들어 30일 동안 결제 요청의 99.9%가 성공해야 한다면 실패를 허용하는 0.1%가 오류 예산입니다. 99.999% 같은 과도한 목표는 개발 속도와 비용을 크게 높일 수 있으므로 사용자 기대와 사업 손실에 맞춰 정해야 합니다.

오류 예산이 충분하면 기능 출시를 계속할 수 있고, 빠르게 소진되면 신규 변경을 줄이고 신뢰성 개선에 집중합니다. 단순 월말 잔여량보다 최근 한 시간과 장기간의 소진 속도, 즉 burn rate를 함께 보면 급격한 장애와 서서히 악화되는 문제를 모두 감지할 수 있습니다.
좋은 알림은 원인이 아니라 사용자 증상에서 시작한다
CPU가 80%를 넘었다는 사실만으로 새벽에 사람을 깨우면 알림 피로가 생깁니다. CPU가 높아도 사용자가 정상적으로 서비스를 쓸 수 있고 자동 확장이 대응한다면 즉각적인 호출이 필요하지 않을 수 있습니다. 반대로 CPU는 낮아도 결제 실패율이 급증하면 바로 대응해야 합니다.
호출 알림은 긴급성, 사용자 영향, 담당자가 지금 할 수 있는 행동이 모두 있을 때 발송합니다. 티켓으로 처리할 수 있는 용량 추세와 보안 인증서 만료 예고는 페이지 알림과 분리합니다. 각 알림에는 영향 범위, 관련 대시보드와 최근 배포, 확인할 런북, 임시 완화 방법을 연결합니다.
같은 장애가 서비스별 알림 수십 개를 만들지 않도록 상위 사용자 증상을 중심으로 묶고 하위 원인 신호는 조사 자료로 제공합니다. 알림 횟수, 오탐률, 응답 없이 닫힌 비율도 운영 지표로 관리해야 합니다.
대시보드는 그래프 모음이 아니라 의사결정 화면이다
좋은 서비스 대시보드 첫 화면에는 요청량, 성공률, 지연, SLO 소진, 주요 의존성이 보입니다. 그래프마다 정상 범위와 배포·플래그 변경 시각이 함께 표시되어야 변화의 맥락을 알 수 있습니다. 모든 인프라 지표를 한 화면에 넣기보다 질문별로 계층화합니다.
운영 개요에서 문제가 있는 사용자 여정을 선택하고, 서비스별 RED, 특정 route와 지역, trace 예시와 관련 로그로 내려가는 탐색 경로를 설계합니다. 고객센터도 주문 ID나 사용자용 오류 ID로 trace를 찾을 수 있으면 개발팀과의 왕복 시간이 크게 줄어듭니다.
관측 비용도 시스템의 일부다
로그와 트레이스는 트래픽과 함께 빠르게 증가합니다. 모든 데이터를 같은 기간, 같은 고성능 저장소에 보관하면 비용이 서비스 인프라 비용을 넘어설 수 있습니다. 신호별 목적에 맞춰 보존 기간, 샘플링, 집계와 저장 계층을 정해야 합니다.
- 디버그 로그는 짧게 보존하고 필요할 때 제한적으로 활성화합니다.
- 감사 로그는 별도 보안 정책과 긴 보존 기간을 적용합니다.
- 메트릭은 오래된 원본 해상도를 낮춰 장기 추세만 보존합니다.
- 정상 trace는 샘플링하고 오류·고지연 trace는 우선 보존합니다.
- 팀별 데이터 사용량과 고카디널리티 속성 예산을 보여줍니다.
비용 절감 과정에서 사고 조사에 필요한 유일한 데이터를 없애지 않도록 실제 조회 빈도와 장애 사례를 기준으로 조정합니다. 수집량, 저장량, 쿼리 비용과 폐기된 데이터 비율 자체도 메트릭으로 관찰할 필요가 있습니다.
자주 실패하는 관측 가능성 도입 방식
첫 번째는 도구부터 구매하고 무엇을 알고 싶은지 나중에 정하는 방식입니다. 데이터는 많지만 핵심 사용자 여정의 성공 여부가 없습니다. 두 번째는 모든 서비스가 서로 다른 필드와 이름을 사용하는 경우입니다. 같은 오류를 팀마다 다른 쿼리로 찾아야 합니다.
세 번째는 대시보드를 만들고 알림과 런북을 연결하지 않는 것입니다. 장애를 보더라도 담당자와 대응 방법을 알 수 없습니다. 네 번째는 계측을 한 번의 프로젝트로 끝내는 것입니다. 서비스 구조와 핵심 기능이 바뀌면 SLI, span과 로그 스키마도 함께 갱신해야 합니다.
작게 시작하는 구현 순서
- 가장 중요한 사용자 여정 하나를 고릅니다. 예를 들어 주문 생성부터 결제 완료까지의 성공 조건과 지연 목표를 정의합니다.
- 공통 컨텍스트를 정합니다. trace ID, request ID, service, version, region과 업무 식별자의 명명 규칙을 통일합니다.
- RED 메트릭과 구조화 완료 로그를 추가합니다. 성공·실패와 지연을 먼저 볼 수 있게 합니다.
- 서비스 경계에 trace context를 전파합니다. HTTP, DB, 큐와 외부 API 구간을 연결합니다.
- SLI와 임시 SLO를 운영합니다. 몇 주간 데이터를 보고 목표가 사용자 기대를 잘 반영하는지 조정합니다.
- 증상 기반 알림과 런북을 만듭니다. 실제 장애 훈련으로 탐지와 조사 시간을 측정합니다.
- 비용과 품질을 함께 점검합니다. 누락된 trace, 과도한 로그, 고카디널리티를 지속적으로 정리합니다.
관측 가능성은 데이터를 모으는 일이 아니라 질문에 답하는 능력이다
운영 중인 시스템은 예상한 방식으로만 실패하지 않습니다. 중요한 것은 모든 상황을 미리 대시보드로 만드는 것이 아니라, 사용자의 이상을 발견한 뒤 어느 서비스와 배포, 데이터와 외부 의존성이 원인인지 빠르게 좁힐 수 있는 연결된 증거를 남기는 것입니다.
핵심 원칙을 요약하면 이렇습니다. 사용자 여정에서 시작하고, 세 신호를 공통 컨텍스트로 연결하며, SLO로 정상과 위험을 정의하고, 사람이 행동할 수 있는 알림만 보낸다. 이 원칙이 지켜질 때 관측 도구는 그래프 저장소가 아니라 장애 시간을 줄이고 제품 품질을 높이는 운영 시스템이 됩니다.