01 · 카디널리티 — 시계열 폭발의 원리와 설계 원칙
- 시계열 = 지표 이름 + 레이블 집합. 레이블 값 하나만 달라도 완전히 다른 시계열이 됩니다.
- New TSID 발급(=처음 보는 시계열)이 곧 카디널리티 폭발입니다. IndexDB에 인덱스를 쓰는 연산이라 데이터포인트 추가보다 CPU·메모리를 훨씬 많이 먹습니다.
- Worst case는
pod_name·session_id처럼 자주 바뀌는 값을 레이블로 쓰는 것입니다. Best case는 설계 단계에서 배제하는 것 — 서비스 이름 같은 안정 레이블만 쓰고 자주 바뀌는 값은 로그·트레이스로 뺍니다. - 런타임에는 churn rate(신규 시계열 생성 속도)와 slow insert rate(지속 10% 초과 시 메모리 부족 경고)를 봅니다.
VM 운영에서 가장 자주 사고를 내는 개념이 카디널리티입니다. 출발점은 “한 시계열이 무엇으로 정의되는가"입니다. 거기서 카디널리티 폭발이 왜 곧 메모리·인덱스 폭발인지, 설계 단계에서 어떻게 막는지까지 이어 봅니다.
관련 문서: 개념 04 저장, 개념 05 쿼리·운영 컴포넌트, 02 대규모 운영
한 시계열 = 지표 이름 + 레이블 집합
도식 텍스트
- metric 이름 + 레이블 집합 — = 1 시계열
- Worst — pod_name · session_id — 재시작·요청마다 변경 → New TSID 폭발
- Best — 서비스 이름 등 안정 레이블 — 자주 바뀌는 값은 로그·트레이스로
VM에서 하나의 시계열은 “지표 이름 + 레이블 집합"으로 정의됩니다.
레이블이 단 하나만 달라져도 완전히 다른 시계열로 인식됩니다.
아래 둘은 지표 이름이 같은데도 별개의 시계열 두 개로 셉니다.
http_requests_total{service="my-order", pod="my-order-7f9c-abcde"}
http_requests_total{service="my-order", pod="my-order-7f9c-xyz12"}
└─ pod 값 하나만 달라도 별개의 시계열카디널리티란 이렇게 나뉜 서로 다른 시계열의 총 개수입니다. 레이블 값의 조합이 늘어날수록 곱셈으로 불어납니다.
New TSID 폭발이 곧 카디널리티 폭발
개념 04 저장에서 본 저장 경로를 다시 떠올려 봅니다. vmstorage는 들어온 지표를 TSID로 변환합니다. 조회 순서는 TSID 캐시 → IndexDB입니다. 둘 다 없으면 처음 보는 시계열로 판단해 New TSID를 발급합니다.
TSID 캐시 조회 → miss
→ IndexDB(디스크 인덱스) 조회 → miss
→ 처음 보는 시계열 → New TSID 발급 (인덱스 쓰기)New TSID가 마구 발급되는 상황이 곧 카디널리티 폭발입니다. 레이블이 계속 새 값으로 바뀌면 매번 “처음 보는 시계열"이 됩니다. New TSID가 끝없이 찍힙니다. New TSID 발급은 데이터포인트 하나를 추가하는 일과 차원이 다릅니다. IndexDB에 새 엔트리를 쓰는 인덱스 연산이라 CPU·메모리를 훨씬 많이 먹습니다. 그래서 카디널리티 폭발은 곧바로 IndexDB 팽창과 메모리 압박, OOM 위험으로 이어집니다(→ 02 대규모 운영에서 실제 vmstorage 메모리 한계로 나타납니다).
Worst Case — 자주 바뀌는 값을 레이블로
자주 변경되는 값을 레이블에 넣는 것이 카디널리티를 터뜨리는 전형적인 실수입니다.
- 파드 이름(
pod): 쿠버네티스에서 파드는 재시작·재배포마다 이름이 바뀝니다. 파드가 한 번 재시작될 때마다 그 지표의 시계열이 통째로 새것이 됩니다. 이전 시계열은 죽은 채 인덱스에 남습니다. - 세션 ID(
session_id): 요청·세션마다 유일한 값이라 사실상 무한대로 늘어납니다. 이런 레이블 하나가 시계열 수를 폭발적으로 늘립니다.
둘 다 값의 가짓수가 시간이 지나며 계속 늘어납니다. 이런 레이블은 시계열 교체율(뒤의 churn)을 끌어올려 인덱스를 부풀립니다.
레이블이 왜 곱셈으로 불어나는지는 숫자로 보면 분명합니다. 아래는 감을 잡으려고 세워 본 가상의 계산 예시입니다 — 실측치가 아닙니다. 레이블 조합이 어떻게 곱해지는지 보려고 만든 숫자입니다. http_requests_total 지표 하나에 레이블을 한 겹씩 더해 가며 시계열 수를 세어 봅니다.
| 얹는 레이블 | 새 가짓수(가정) | 누적 시계열 수 |
|---|---|---|
http_requests_total (메트릭 1개) | — | 1 |
× service | 10 | 10 |
× pod (서비스당 활성 5개) | 5 | 50 |
× path | 20 | 1,000 |
+ session_id (요청마다 유일) | 수십만~∞ | 사실상 무한 |
service·pod·path까지는 1,000개로 유한합니다. 그런데 worst case인 session_id를 한 겹 더 붙이면 마지막 항이 사실상 무한대입니다. 전체 곱이 통제 불능으로 튑니다. 곱셈은 한 항만 무한히 늘어도 전체가 무한히 늘어납니다. 고카디널리티 레이블 하나로 클러스터가 무너지는 원리입니다. (pod도 순간에는 유한합니다. 재시작마다 새 이름이 쌓이니 시간이 지날수록 churn으로 이 수마저 계속 커집니다.)
Best Case — 설계에서 배제하는 것이 가장 싸다
설계 단계에서 고카디널리티 레이블을 아예 만들지 않는 쪽이 쿼리 튜닝보다 확실합니다.
- 자주 바뀌어 High Cardinality를 유발하는 레이블은 처음부터 설계에 넣지 않는 편이 낫습니다. 한 번 들어간 레이블을 나중에 걷어내기는 훨씬 어렵습니다.
- 파드 이름 대신 서비스 이름을 씁니다. 파드 이름(
my-order-7f9c-abcde)은 재시작마다 바뀌지만 서비스 이름(my-order)은 잘 바뀌지 않습니다. 서비스 이름을 레이블로 쓰면 파드가 재시작돼도 시계열이 그대로 유지됩니다. - 자주 바뀌는 값은 지표 대신 로그·트레이스로 다룹니다. 세션 ID처럼 개별 요청을 추적해야 하는 값은 metric의 레이블이 아니라 로그나 트레이스에 담습니다. 지표는 집계하는 도구이고 개별 식별자 추적은 로그·트레이스의 몫입니다.
설계로 배제하는 쪽이 낫지만 이미 돌고 있는 클러스터라면 현재 카디널리티를 직접 확인할 수 있습니다. vmstorage(단일 노드 포함)의 /api/v1/status/tsdb 엔드포인트가 전체 활성 시계열 수를 알려 주고, 카디널리티가 높은 상위 메트릭·레이블도 함께 요약해 줍니다. 시각적으로 파고들려면 vmui의 Cardinality Explorer(/vmui/#/cardinality)를 씁니다. 어떤 메트릭·레이블 값이 시계열을 많이 먹는지 훑을 수 있습니다. 구체적인 확인 쿼리와 우리 환경의 인벤토리 도구는 우리의 운영 03 자기감시 메트릭에 정리해 두었습니다.
운영 감시 지표 — churn rate와 slow insert rate
카디널리티는 배포 이후에도 계속 변하므로 런타임에 감시해야 합니다. 다음 지표를 봅니다.
- 시계열 교체율 (churn rate) · 24시간 안에 새로 생성된 시계열의 수와 비율(=New TSID 발급 속도) — 값이 커질수록 IndexDB 부하가 늘고 OOM과 쿼리 성능 저하 가능성이 커집니다.
- 지연 삽입 비율 (slow insert rate) · 최근 5분 동안 전체 수집량 대비 지연된 삽입의 비율 — 지속적으로 10%를 넘으면 현재 활성 시계열 수에 비해 메모리가 부족하다는 신호입니다.
churn rate는 앞서 본 New TSID 발급을 그대로 관측한 값입니다. 자주 바뀌는 레이블이 들어오면 이 수치가 튑니다. slow insert rate는 TSID 캐시가 메모리 부족으로 미스를 자주 내며 IndexDB 폴백이 잦아질 때 오릅니다. 활성 시계열이 메모리 캐시에 다 담기지 못한다는 뜻입니다. 지속적으로 10% 초과는 “메모리가 활성 시계열을 감당하지 못한다"는 명확한 경고로 읽어야 합니다.
이 두 지표는 02 대규모 운영의 무중단 장비 전환에서 실전 계기판으로 쓰입니다. 12.5억 시계열 규모에서 -storageNode 목록을 어떻게 바꿔야 안전한지를 이 두 값으로 판단합니다. 목록을 통째로 교체하면 신규 장비의 모든 시계열이 New TSID로 재등록되기 때문입니다. 그러면 churn이 폭등하고 클러스터가 OOM에 빠질 수 있습니다.
출처
- Inside VictoriaMetrics (강민구, NAVER) — 시계열 정의·New TSID 발급·Best/Worst Case: 20:52
21:38, 38:5039:55 구간. (https://d2.naver.com/helloworld/9290861) - 네이버 검색의 대규모 메트릭 저장소, VictoriaMetrics 운영기 (2026) — churn rate·slow insert rate 지표와 10% 임계. (https://d2.naver.com/helloworld/6475419)
- 합성 골격:
chapter9/victoriametrics.md§6.