구글 SRE의 4가지 골든 시그널(지연시간, 트래픽, 에러율, 포화도)로 정하는 모니터링 지표
On this page
구글 SRE의 4개의 골든 시그널(지연시간, 트래픽, 에러율, 포화도)로 정하는 모니터링 지표
안녕하세요, DevOps 챕터의 sabo입니다.
장애 알림을 받고 대시보드를 열었는데, 그래프가 너무 많아서 정작 어디부터 봐야 할지 막막했던 적 있으신가요? 반대 경우도 흔합니다. CPU도 메모리도 멀쩡한데 사용자 문의는 쏟아지고 있거나, CPU 알림은 시도 때도 없이 울리는데 서비스는 아무 문제가 없거나. 무엇을 볼지 미리 정해 두지 않으면 생기는 일들입니다.
이 질문에 대한 가장 유명한 답이 구글 SRE 북의 Monitoring Distributed Systems 챕터에 있는 4가지 골든 시그널(Four Golden Signals)입니다. 요즘은 옵저버빌리티(observability)라는 더 넓은 말을 많이 쓰는데요. 메트릭·로그·트레이스를 묶어 예상 못 한 문제까지 추적하는 능력이 옵저버빌리티라면, 이 글이 다루는 건 그 출발점인 모니터링 — 그중에서도 "어떤 지표를 볼 것인가"입니다. 저는 이 내용이 인프라를 만지는 엔지니어들(DevOps, 시스템, 클라우드엔지니어등)만이 아니라 백엔드 개발자에게도 필요하다고 생각합니다. 지표를 보는 눈이 없으면 자기가 만든 서비스가 지금 장애인지 아닌지를 남이 알려줄 때까지 모르게 되니까요.
왜 하필 네 개인가
지표 후보는 끝이 없습니다. CPU, 메모리, 디스크, 네트워크, GC, 스레드, 큐 길이, DB 커넥션 풀, 응답 시간, 처리량, 동시 요청 수… 전부 다 보겠다고 대시보드에 쌓다 보면, 장애 순간에는 오히려 그 양에 파묻힙니다. 구글 SRE 북은 여기에 선을 그어 줍니다. B2C 서비스 시스템에서 딱 네 가지만 측정할 수 있다면 지연 시간(Latency), 트래픽(Traffic), 에러율(Errors), 포화도(Saturation)에 집중하라고요.
PS. 모니터링 지표 프레임워크가 4 Golden Signals만 있는 건 아닙니다. 업계에서 같이 언급되는 게 두 개 더 있습니다.
| 프레임워크 | 제안자 | 관점 | 구성 |
|---|---|---|---|
| 4 Golden Signals | 구글 SRE | 사용자 경험·서비스 품질 | 지연 시간·트래픽·에러율·포화도 |
| RED Method | Tom Wilkie (현 Grafana Labs) | 요청 기반 서비스 | Rate·Errors·Duration |
| USE Method | Brendan Gregg | 시스템 리소스 | Utilization·Saturation·Errors |
RED의 Rate·Errors·Duration은 골든 시그널의 트래픽·에러율·지연 시간과 같은 것이라, RED는 사실상 골든 시그널에서 포화도만 뺀 것입니다. USE는 서비스가 아니라 CPU·디스크 같은 리소스 하나하나에 적용하는 방법론이라, 골든 시그널 중에서는 포화도와 맞닿습니다(Utilization은 골든 시그널에 대응 항목이 없습니다). 그래서 정의상 역할이 이렇게 갈립니다 — 골든 시그널로 서비스 이상을 감지하고, RED 관점으로 어느 서비스·API가 문제인지 좁히고, USE 관점으로 병목 리소스를 찾는 조합이 자연스럽습니다.
① 지연 시간 — 평균만 보면 진짜 문제가 있는 사용자를 놓친다
지연 시간(Latency)은 요청을 보낸 순간부터 응답을 받기까지의 시간, 즉 사용자가 체감하는 속도입니다. 여기서 흔한 함정이 평균입니다. 평균 응답이 100ms라도 상위 1% 사용자는 5초를 기다리고 있을 수 있는데, 평균은 이걸 완전히 가려 버립니다. 그래서 P95·P99 같은 꼬리 지연(tail latency) — 전체 요청의 95%, 99%가 이 시간 안에 처리된다는 값 — 을 봐야 하고, 많은 서비스가 이걸 서비스 품질을 재는 대표 숫자인 서비스 수준 지표(SLI)로 삼습니다.
분산 시스템이라면 꼬리 지연의 무게가 훨씬 커집니다. 요청 하나가 내부 서버 100대로 동시에 갈라져 나갔다가(팬아웃) 모든 응답이 모여야 완성되는 구조라면, 각 서버가 100번에 1번만 1초 이상 걸려도 사용자 요청의 63%가 1초를 넘깁니다. 1 − 0.99¹⁰⁰ 계산이고, 구글의 The Tail at Scale 논문(Dean & Barroso, CACM 2013)에 나오는 예시입니다. 팬아웃이 큰 마이크로서비스 구조일수록 P99가 곧 보통 사용자의 경험이 됩니다.
여기서 자주 빠뜨리는 포인트가 하나 있습니다. 성공 응답과 실패 응답의 지연 시간을 분리하되, 실패 쪽을 버리지 말라는 겁니다. DB 연결이 끊겨 즉시 500으로 실패하는 요청은 아주 빨라서, 전체 평균에 섞으면 응답 시간이 오히려 좋아 보이는 왜곡이 생깁니다. 그리고 원문에는 이런 문장이 있습니다.
"a slow error is even worse than a fast error"
즉시 500이 떨어지면 사용자는 바로 재시도라도 할 수 있습니다. 하지만 30초 타임아웃까지 붙잡아 두고 나서 실패하면, 사용자는 그 시간을 통째로 날린 끝에 실패까지 당합니다. 그래서 실패 응답을 걸러내고 끝낼 게 아니라, 실패 응답의 지연 시간 자체를 별도 지표로 추적해야 합니다.
② 트래픽 — 부하의 시작점
트래픽(Traffic)은 시스템에 지금 얼마나 많은 요구가 걸리고 있는가, 원문 표현으로는 시스템에 걸리는 수요(demand)의 크기입니다. 서비스 유형마다 단위가 다릅니다. 웹 서비스라면 초당 HTTP 요청 수(RPS), 스트리밍이라면 동시 세션 수나 네트워크 I/O, 키-값 저장소라면 초당 트랜잭션·조회 수(TPS)가 되겠죠.
트래픽이 골든 시그널에 들어가는 이유는 단순히 "많이 들어오나"를 보기 위해서가 아닙니다. 트래픽은 시스템에 들어오는 부하의 시작점이고, 나머지 세 지표는 결국 이 부하가 시스템을 통과하면서 만들어 내는 결과입니다. 이 관계는 뒤에서 다룰 포화도의 인과 관계에서 다시 나옵니다.
③ 에러율 — 5xx error만 체크하면 명시적 실패만 보는 것
에러율(Errors)은 전체 요청 중 실패한 요청의 비율입니다. 뻔해 보이지만, HTTP 5xx만 세고 있다면 세 갈래 중 한 갈래만 보고 있는 겁니다. 원문은 실패를 이렇게 구분합니다.
"either explicitly (e.g., HTTP 500s), implicitly (e.g., an HTTP 200 success response, but coupled with the wrong content), or by policy"
- 명시적 실패 — HTTP 5xx처럼 프로토콜 레벨에서 바로 드러나는 오류. 인프라 모니터링이 잡아 주는 영역입니다.
- 묵시적 실패 — 응답은 200인데 내용이 잘못된 경우. 주문 API가 200을 돌려줬지만 주문이 실제로 저장되지 않았다면 사용자 입장에서는 명백한 실패인데, 상태 코드만 보는 모니터링에는 아무것도 안 잡힙니다. 그래서 E2E 테스트나 애플리케이션 레벨 검증이 필요합니다.
- 정책적 실패 — 응답은 왔지만 서비스 수준 목표(SLO)를 어긴 경우. 원문 예시가 명쾌합니다. 1초 안에 응답하기로 약속했다면, 1.5초 걸린 성공 응답도 약속 기준으로는 실패라는 겁니다.
세 번째 분류가 말해 주는 건, 에러율의 기준이 기술이 아니라 비즈니스 약속에서 나온다는 사실입니다. 같은 응답이라도 SLO가 다르면 성공과 실패가 갈립니다.
④ 포화도 — 한계치를 모니터링하면 이미 늦다
포화도(Saturation)는 시스템에서 가장 병목이 되는 리소스가 한계에 얼마나 가까워졌는가입니다. 고속도로를 떠올리면 됩니다. 차선이 꽉 차기 한참 전부터 정체는 시작되죠. 시스템도 같습니다. 대기행렬 이론에서 평균 대기 시간은 사용률을 ρ라 할 때 1/(1−ρ)에 비례해 늘어납니다. 사용률 90%의 대기가 80%의 두 배라는 뜻입니다. 이렇게 사용률이 오를수록 대기가 가파르게 길어지기 때문에, 많은 시스템이 리소스 100%에 도달하기 전에 성능 저하를 먼저 겪습니다. 그래서 "CPU 80% 이상이면 위험" 같은 목표 사용률(utilization target)을 팀 기준으로 미리 정해 두라는 겁니다. 임계값 자체는 시스템 특성과 워크로드에 따라 다릅니다.
측정 대상은 CPU, 메모리, 스레드풀, 큐 길이, 디스크 I/O, 네트워크 대역폭처럼 여러 가지지만, 원문의 조언은 그중 가장 제약이 심한 리소스에 집중하라입니다. 꼬리 지연이 갑자기 튀는 건 포화의 대표적인 전조증상입니다. 원인 순서로는 포화가 먼저지만 관측은 지연 쪽이 먼저 눈에 띄는 경우가 많아서, P99가 이상하면 어떤 리소스가 차오르고 있는 건 아닌지부터 의심해 볼 만합니다.
포화도에서 자주 빠지는 부분이 하나 더 있는데, 원문은 지금 수치만이 아니라 예측까지 포화도의 일부로 봅니다.
"It looks like your database will fill its hard drive in 4 hours."
지금 디스크가 70%라는 사실보다, 증가 추세를 보니 곧 가득 찬다는 예측이 훨씬 값진 경보라는 거죠. 순간 임계치 알림과 추세 기반 예측 알림은 잡아 주는 문제가 달라서 같이 걸어 둬야 합니다.
4개의 지표는 사슬로 이어져 있다
4개의 지표는 따로 노는 게 아니라 서로 연결됩니다. 과부하형 장애의 전형적인 전개가 이렇습니다.
트래픽 급증 → 포화도 상승 → 지연 시간 증가 → 에러 발생
부하가 원인인 장애에서 이 패턴이 나타나는 건 우연이 아니라, 각 단계가 다음 단계의 직접 원인이기 때문입니다. 들어오는 요구가 늘면 리소스가 차고, 리소스가 차면 대기가 길어지고, 대기가 한계를 넘으면 타임아웃과 에러가 됩니다.
예를 들어 푸시 알림이 나간 직후를 생각해 보죠. 유입이 평소의 세 배로 뜁니다(트래픽). 곧 DB 커넥션 풀이 바닥나기 시작하고(포화도), 풀에서 커넥션이 나기를 기다리는 요청들 때문에 P99가 튀고(지연 시간), 결국 대기가 타임아웃을 넘기면서 5xx가 쏟아집니다(에러). 이때 CPU 그래프만 보고 있었다면 마지막 단계까지 아무것도 몰랐을 수 있습니다. 커넥션을 기다리는 스레드는 CPU를 거의 안 쓰거든요. 반대로 트래픽 그래프를 보고 있었다면 첫 단계에서 이미 손쓸 시간을 벌었을 겁니다. 여기서 "트래픽을 가장 먼저 실시간으로 보라"는 실무 조언이 나옵니다 — 사슬의 출발점이 가장 먼저 움직이는 선행 신호니까요. 다만 이건 4가지 지표간의 연관 관계에서 나온 해석이지, SRE 북 원문에 4가지 지표의 우선순위가 정해져 있는 건 아닙니다. DB 데드락이나 외부 API 장애처럼 트래픽 변화 없이 에러부터 나는 장애도 흔하고요.
대시보드도 이 순서를 따라 트래픽 → 포화도 → 지연 시간 → 에러율로 배치해 두면, 장애 때 시선이 자연스럽게 원인 추적 방향을 따라가게 됩니다.
Kubernetes/Istio 환경이라면 이미 절반은 나와 있다
저희는 Kubernetes 위에 Istio 서비스 메시를 쓰고 있는데요. 이 구성이라면 골든 시그널 네 개 중 세 개는 애플리케이션 코드에 손대지 않아도 이미 수집되고 있습니다. Istio는 각 파드에 프록시 컨테이너(사이드카)를 붙여 모든 요청이 그걸 통과하게 하는 구조라, 이 프록시가 요청마다 표준 메트릭을 대신 기록해 주기 때문입니다.
istio_requests_total— 요청 수와 응답 코드가 담겨 있어 트래픽과 에러율이 여기서 나옵니다.istio_request_duration_milliseconds— 요청 시간을 구간(버킷)별로 세는 히스토그램이라 P95·P99를 계산할 수 있습니다.
Prometheus 쿼리로는 이런 식입니다. 한 요청을 보내는 쪽과 받는 쪽 프록시가 각각 기록하기 때문에, reporter="destination"으로 한쪽만 골라야 이중 계산이 없습니다.
# 서비스별 에러율 (5xx 비율, 최근 5분)
sum(rate(istio_requests_total{reporter="destination", response_code=~"5.."}[5m])) by (destination_service_name)
/ sum(rate(istio_requests_total{reporter="destination"}[5m])) by (destination_service_name)
# 서비스별 P99 지연 시간
histogram_quantile(0.99,
sum(rate(istio_request_duration_milliseconds_bucket{reporter="destination"}[5m])) by (le, destination_service_name))붙여 두면 좋은 주의점 두 가지. 위 에러율 쿼리는 5xx가 하나도 없는 서비스를 결과에서 통째로 빼 버립니다("에러율 0%"가 아니라 "그래프에 없음"이 되죠). 그리고 histogram_quantile은 버킷 경계 사이를 선형 보간한 근사값이라, 관심 구간에 버킷 간격이 듬성듬성하면 P99가 실제와 어긋납니다. Istio 기본 버킷으로 부족하면 버킷 조정이 필요합니다.
포화도는 사정이 다릅니다. Istio 표준 메트릭 세트에는 포화도가 없습니다. 프록시(Envoy) 통계에 커넥션 풀·서킷 브레이커 같은 포화 신호가 있긴 하지만, 무엇을 "가득 찼다"고 볼지는 서비스마다 달라 결국 직접 정의해야 합니다. 노드·파드의 CPU와 메모리(파드에 걸어 둔 상한 limit 대비 실제 사용량), 커넥션 풀 점유율, 큐 길이 같은 걸 워크로드 특성에 맞게 붙이면 됩니다. 코드 수정 없이 얻는 세 개에 포화도 하나만 채우면 기본 골격이 완성됩니다.
모니터링시스템의 마무리는 알림시스템이죠. 골든 시그널로 지표를 골랐다면, 알림은 원인(CPU 높음)이 아니라 증상(사용자가 겪는 실패·지연. Burn Rate) 기준으로 거는 것이 SRE 워크북의 권고입니다. 구체적인 방법은 Alerting on SLOs 을 참고하세요.
마치며
정리하지 않으면 지표는 계속 늘기만 합니다. 그래서 한 가지만 권하면서 마치겠습니다. 대시보드 첫 화면에는 최대한 4가지 지표만 남기고, 나머지는 전부 다음 페이지로 내려 보는것을 고려해보세요. 첫 화면의 배치는 트래픽 → 포화도 → 지연 시간 → 에러율. 장애 순간에 어디부터 볼지 고민하는 시간이 사라지는 것만으로도 충분히 메리트가 있을겁니다.
이 글은 구글 SRE 북 원문을 기준으로 정리했습니다. 주제를 처음 접한 건 아래 한국어 해설 영상 덕분이었는데, 원문의 뼈대를 잘 추려 주어 입문용으로 권합니다. 비슷한 고민을 하는 분들께 도움이 되길 바랍니다.
참고 자료