LabHub

관측성 · 카디널리티 폭발 · 이론

라벨에 user_id 를 넣으면 안 되는 이유

LabHub 에서 이어서 보기

한 줄 요약

메트릭의 시계열 개수는 라벨 값 조합의 입니다. 라벨 하나를
잘못 고르면 시계열이 수백만 개가 되고, 그 순간 모니터링 시스템이
관측 대상보다 먼저 죽습니다.

왜 이게 필요했나

http_requests_total 에 라벨을 붙입니다.

http_requests_total{method, status, endpoint}

시계열 개수는 5 × 8 × 40 = 1,600개. 괜찮습니다.

여기에 "사용자별로 보고 싶다" 는 요청이 들어와 user_id 를 추가합니다.
사용자가 10만 명이면,

5 × 8 × 40 × 100,000 = 1억 6천만 개.

프로메테우스는 시계열마다 메모리에 인덱스를 유지합니다. 서버가 OOM 으로
죽고, 그러면 장애를 관측할 수단이 장애 때문에 사라집니다.

카디널리티 폭발을 만드는 라벨들

절대 라벨에 넣지 말아야 할 것들입니다.

| 라벨 | 왜 위험한가 |
| --- | --- |
| user_id, session_id | 사용자 수만큼 증가. 상한이 없다 |
| request_id, trace_id | 요청마다 고유. 무한 |
| email, ip | 사실상 무한 + 개인정보 |
| timestamp | 시간마다 새 시계열 (시계열에 시간을 넣는 모순) |
| url (쿼리스트링 포함) | ?page=1, ?page=2… 무한 |
| 에러 메시지 전문 | 메시지에 값이 섞이면 무한 |

특히 마지막. error="connection to 10.0.3.17:5432 timed out" 처럼
IP·포트가 들어간 메시지를 라벨로 쓰면 조합이 폭발합니다.
error="db_timeout" 처럼 분류된 값을 씁니다.

판단 기준 — 이 라벨의 값은 몇 가지인가

라벨을 추가하기 전에 스스로 묻습니다.

1. 가능한 값이 몇 개인가? 세어서 답할 수 있어야 합니다. "많아요" 는
답이 아닙니다.
2. 시간이 지나면 늘어나는가? 늘어난다면 상한이 있는가?
3. 이 라벨로 실제 알림을 만들 것인가? 대시보드에서 한 번 볼 것 같다면
메트릭이 아니라 로그나 트레이스로 가야 합니다.

경험칙으로 라벨 하나당 값 100개 이하, 메트릭 하나당 시계열
1만 개 이하를 목표로 잡습니다.

URL 은 반드시 정규화한다

# 나쁨 — 주문 개수만큼 시계열endpoint="/api/orders/8f3a91"# 좋음 — 라우트 패턴endpoint="/api/orders/:id"

프레임워크의 라우트 정의를 쓰면 자동으로 정규화됩니다. 직접 문자열을
쓰면 반드시 폭발합니다. 이건 실수의 문제가 아니라 시간 문제입니다.

세 신호를 나눠 쓴다

높은 카디널리티 정보가 정말 필요할 때가 있습니다. "이 사용자의 요청이
왜 느렸나" 같은 질문입니다. 그건 메트릭의 일이 아닙니다.

| 신호 | 카디널리티 | 답하는 질문 |
| --- | --- | --- |
| 메트릭 | 낮아야 함 | "얼마나 많이/빠르게?" 추세와 알림 |
| 로그 | 높아도 됨 | "그때 무슨 일이?" 개별 사건 |
| 트레이스 | 높아도 됨 | "시간이 어디서 갔나?" 요청 하나의 경로 |

메트릭으로 알림을 받고 → 시간을 특정하고 → 로그·트레이스로 개별 요청을
파고듭니다. 세 신호는 대체재가 아니라 조사 순서입니다.

이미 폭발했다면

현장에서 만나는 모습

다음 확인에서 볼 것

이어지는 퀴즈에서는 라벨 값의 곱으로 시계열 수를 계산하고, 메트릭과 로그·트레이스의
역할을 구분합니다. 이미 폭발이 시작된 상황에서 수집 단계 완화와 애플리케이션의
근본 수정 중 무엇을 먼저 적용할지도 판단해 보세요.