LabHub
배우기 러닝패스 코스

Observability

The Three Signals Are an Investigation Order, Not Substitutes

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

트레이스는 '어디'에 답하고, 메트릭은 '언제와 얼마나', 로그는 '왜'에 답한다. 그래서 조사 순서는 고정이다 — 메트릭 → 트레이스 → 로그.

Flow map: 라벨에 값이 무한히 많은 것을 넣는 것 · 경로를 가공하지 않고 그대로 넣은 것 · 다른 신호로 옮긴다. · 증상은 대개 대시보드가 아니라 저장소 쪽에서 먼저 나타납니다.

왜 이게 필요했나

장애가 나면 사람들은 대개 로그부터 연다. 그리고 30분 뒤에도 여전히 로그를 읽고 있다. 로그는 가장 자세하지만 가장 비싸고, 무엇을 찾아야 할지 모르는 상태에서 열면 그냥 텍스트의 바다다.

메트릭이 먼저인 이유는 세 가지다. 값이 싸고, 항상 켜져 있고, 카디널리티가 낮다. 이 셋을 동시에 만족하기 때문에 메트릭은 알림의 근거가 될 수 있는 유일한 신호다. 트레이스는 샘플링되므로 "지금 이 순간 나빠지고 있다"를 보장하지 못하고, 로그는 양이 많아 실시간 집계 비용이 감당되지 않는다.

세 신호는 서로를 대체하지 않는다. 서로를 이어 주는 세 개의 다리가 있을 뿐이다. 메트릭에서 트레이스로는 exemplar 로 건너가고, 트레이스에서 로그로는 trace_id 필드로, 로그에서 다시 메트릭으로는 event 필드로 돌아온다. 이 다리가 없으면 세 도구를 다 사 놓고도 조사는 여전히 사람의 직감에 의존한다.

어떻게 동작하나

메트릭에서 진짜 결정은 타입 선택이다. 타입 선택은 취향이 아니다. 잘못 고르면 나중에 하고 싶은 계산이 원리적으로 불가능해진다.

왜 지연 시간에 게이지가 안 되는지는 산수로 확인된다. 스크레이프 간격이 15초이고 초당 요청이 500건이면, 게이지로는 7,500건 중 1건의 값만 저장된다. 나머지는 존재한 적도 없는 것이 된다. 이 시계열로는 p99 를 구할 수 없고 나중에 다시 처리해도 복원되지 않는다.

현장에서 만나는 모습

배포 직후마다 트래픽이 줄어든 것처럼 보이는 대시보드를 종종 만난다. 원인은 거의 항상 같다. rate 를 sum 바깥에 걸어 둔 것이다. 카운터 리셋 보정은 개별 시계열 단위로만 정확하다. 파드 하나가 재시작하면 합산된 뒤에는 리셋으로 인식되지 않는다. 올바른 형태는 sum(rate(x[5m])) by (route) 이고, rate(sum(x)[5m:]) 는 틀렸다.

또 하나는 조용한 오답이다. histogram_quantile 에서 by (le) 를 빼면 에러 없이 틀린 숫자를 반환한다. 아무도 예외를 보지 않으니 그 패널은 몇 달씩 대시보드에 남는다.

카디널리티가 예산을 정한다

메트릭 설계에서 되돌리기 가장 어려운 실수는 라벨에 값이 무한히 많은 것을 넣는 것이다. 시계열의 개수는 라벨 값 조합의 곱으로 늘어난다. 라벨이 셋이고 각각 값이 10·5·4 가지면 시계열은 200개지만, 여기에 사용자 ID 를 하나 더 붙이는 순간 사용자 수만큼 곱해진다. 사용자가 10만 명이면 2천만 개다.

특히 위험한 라벨은 정해져 있다. 사용자 ID, 요청 ID, 세션 ID, 이메일, IP 주소, 그리고 경로를 가공하지 않고 그대로 넣은 것이다. /orders/8213 처럼 식별자가 박힌 경로를 라벨로 쓰면 주문 하나마다 시계열이 하나씩 생긴다. 올바른 형태는 /orders/:id 처럼 라우트 패턴으로 정규화하는 것이고, 이 정규화는 프레임워크가 라우팅할 때 이미 알고 있는 값이라 대개 공짜로 얻을 수 있다.

이렇게 잘라 낸 정보는 버리는 것이 아니라 다른 신호로 옮긴다. 그것이 세 신호를 나눠 두는 이유다.

알고 싶은 것 놓아야 할 곳 이유
이 라우트가 얼마나 느린가 메트릭 값의 종류가 적고 항상 켜져 있어야 한다
이 느린 요청 하나가 어디서 시간을 썼나 트레이스 요청 단위 식별자가 자연스럽게 붙는다
그 요청을 낸 사용자가 누구인가 로그 개수 제한이 없고 검색으로 찾는다

히스토그램은 특히 조심해야 한다. 버킷 하나가 시계열 하나이므로, 버킷 20개짜리 히스토그램에 라벨 조합 200개가 붙으면 그 지표 하나가 4천 개가 넘는 시계열을 만든다. 그래서 히스토그램은 정말 분위수가 필요한 지표에만 쓰고, 버킷 경계는 서비스 수준 목표 근처를 촘촘하게, 나머지는 성기게 잡는다. 목표가 300ms 인데 버킷이 100ms 다음에 바로 1초로 뛰면, p99 가 300ms 를 넘었는지 아닌지를 그 히스토그램으로는 판정할 수 없다.

증상은 대개 대시보드가 아니라 저장소 쪽에서 먼저 나타납니다. 프로메테우스의 메모리가 계속 늘고, 스크레이프가 시간 안에 안 끝나고, 질의가 느려집니다. 이때 topk(10, count by (__name__)({__name__=~".+"})) 로 시계열이 가장 많은 지표부터 세어 보면 범인이 거의 항상 한두 개입니다.

다음 실습에서 할 것

실습 환경에는 진짜 프로메테우스 서버가 12시간치 데이터를 담은 채로 떠 있다. 오류가 치솟는 구간이 두 번, 지연의 꼬리만 튀는 구간이 한 번, 그리고 꾸준히 줄어드는 디스크가 들어 있다.

쿼리를 파일에 적기만 하는 것이 아니라 promq 로 직접 던지고 돌아온 숫자를 읽는다. 여러분이 쓴 쿼리가 그 세 사건을 찾아내는지가 정답 여부를 알려 준다 — PromQL 이 어려운 이유는 문법이 아니라, 틀린 쿼리도 오류 없이 그럴듯한 숫자를 돌려주기 때문이다.