多加了一个标签,时间序列翻了一百倍
한국어 원문으로 표시합니다.
목표
지금 시계열이 무엇에 얼마나 쓰이는지 재고, 라벨을 더했을 때 얼마가 될지 먼저 예측한 뒤 실제로 띄워 확인하고, 예산 상한을 검사 스크립트로 못박아 무엇을 남기고 무엇을 버릴지 결정합니다.
왜 중요한가
카디널리티는 사고가 나기 전에는 아무도 보지 않는 비용이다. 라벨을 하나 더하는 일은 코드 한 줄이지만, 그 라벨의 값이 사용자 수만큼 늘어나면 시계열은 곱으로 늘고 저장과 메모리와 쿼리 시간이 함께 늘어난다. 그리고 그 비용은 '느려졌다' 는 모양으로 나타나서 원인을 찾기 어렵다. 그래서 두 가지를 습관으로 만들어야 한다 — 라벨을 더하기 전에 조합 수를 먼저 곱해 보는 것, 그리고 지표별 시계열 상한을 검사로 못박아 사람이 아니라 파이프라인이 막게 하는 것이다. 무엇을 버릴지 정할 때의 기준은 '이 라벨로 무엇을 결정하는가' 이고, 버린 축이 답하던 질문은 로그나 추적이 대신 답할 수 있는지 함께 확인해야 한다.
단계
/root/obs-cardinality-budget/inventory.tsv를 만드세요.job="shop-api"가 내보내는 지표마다 시계열이 몇 개인지를<지표이름> <시계열 수>두 칸으로, 많은 순서대로 모두 적습니다(다섯 줄입니다). 파드 전체가 아니라 이 잡 하나로 좁히는 이유는, Prometheus 자신이 내는 지표가 실습 도중에도 계속 늘어나 기준이 흔들리기 때문입니다./root/obs-cardinality-budget/labels.tsv를 만드세요. 세 줄이고 각 줄은<라벨이름> <서로 다른 값의 수>입니다.le와handler는 히스토그램 지표http_request_duration_seconds_bucket에서,status는 카운터http_requests_total에서 셉니다(둘 다 job 은 shop-api). 많은 순서대로 적으세요. 그리고/root/obs-cardinality-budget/02-note.txt에top_label=<1위 라벨 이름>과product=<le 값 수 × handler 값 수>두 줄을 적으세요./root/obs-cardinality-budget/cost.txt에 세 줄을 적으세요.series=는job="shop-api"의 시계열 수,samples_per_day=는 그 시계열이 하루에 남기는 표본 수,bytes_per_day=는 그 표본이 차지하는 바이트입니다. 이 파드의 스크레이프 간격은 15초이고, 표본 하나는 평균 2바이트로 잡습니다(Prometheus 저장소 문서가 말하는 1바이트에서 2바이트 사이 중 보수적인 쪽). 세 값은 서로 곱셈으로 맞아떨어져야 합니다.- 새 지표
checkout_requests_total을 내보내려 합니다. 라벨은region(ap1·ap2·us1·eu1),tier(free·pro·team),endpoint(cart·pay·refund·ship·track) 셋입니다./root/obs-cardinality-budget/forecast.txt에formula=와predicted_series=두 줄을 적으세요. formula 는 곱셈식(예:2*3*4), predicted_series 는 그 결과입니다. 아직 아무것도 띄우지 마세요. /root/obs-cardinality-budget/exporter.py를 만드세요. 인자로--print를 주면 노출 텍스트를 표준 출력에 찍고 끝나고, 인자가 없으면 127.0.0.1:9102 에서/metrics를 서비스합니다. 4단계의 세 라벨 조합마다checkout_requests_total한 줄을 냅니다. 환경 변수USERS가 0 보다 크면user_id라벨이 붙습니다. 그다음/etc/prometheus/prometheus.yml에cardinality-lab이라는 스크레이프 잡을 더하고 설정을 다시 읽히세요. 첫 스크레이프가 끝난 뒤/root/obs-cardinality-budget/measured.txt에measured_series=<수>한 줄을 적습니다.USERS=100으로 exporter 를 다시 띄워user_id라벨을 붙이세요./root/obs-cardinality-budget/explode.tsv에 두 줄을 적습니다. 각 줄은 탭으로 나눈 세 칸<이름> <시계열 수> <하루 바이트>이고, 첫 줄의 이름은before(user_id 없이), 둘째 줄은after(user_id 포함)입니다. 하루 바이트는 3단계와 같은 방식(시계열 × 5760 × 2)으로 계산합니다./root/obs-cardinality-budget/budget.sh를 만드세요.bash budget.sh <상한표>로 부르면 상한표의 각 줄 (<지표이름> <최대 시계열 수>)마다 지금 시계열 수를 세어<지표이름> <지금> <상한> OK또는... OVER를 한 줄씩 출력하고, 하나라도 상한을 넘으면 종료 코드 1, 아니면 0 으로 끝납니다. 그리고/root/obs-cardinality-budget/caps.tsv에checkout_requests_total의 상한을 500 으로 적고 그 표로 한 번 돌려 출력을/root/obs-cardinality-budget/gate-out.txt에 저장하세요.- 시계열 상한이 500 입니다.
/root/obs-cardinality-budget/decision.txt에 네 줄을 적으세요.keep=에는 남길 라벨 이름을 쉼표로(예:region,tier),drop=에는 버릴 라벨 이름을 쉼표로,projected_series=에는 남긴 라벨만으로 계산한 시계열 수를,lost_question=에는 그 라벨을 버렸을 때 더 이상 답할 수 없게 되는 질문을 30자 이상으로 적습니다. 라벨의 값 개수는 region 4 · tier 3 · endpoint 5 · user_id 100 입니다.
참고
- 작업 디렉터리는
/root/obs-cardinality-budget입니다. - TSDB 상태:
curl -s 'http://127.0.0.1:9090/api/v1/status/tsdb?limit=5' | jq—headStats·seriesCountByMetricName·labelValueCountByLabelName을 봅니다. - 설정 반영:
curl -X POST http://127.0.0.1:9090/-/reload. 스크레이프 간격이 15초라 첫 값까지 조금 걸립니다. - 흔한 실수:
count()결과가 비었을 때 0 으로 보지 않아 게이트가 오류로 끝나는 것. - 흔한 실수: 라벨 값이 독립이라고 가정하고 곱했는데 실제로는 일부 조합만 존재하는 경우 — 예측은 상한이고, 실측이 그보다 작으면 그 차이도 정보입니다.
- Storage · TSDB status API · Instrumentation practices · Naming
한 서비스의 시계열이 어디에 쓰이는지 센다
/root/obs-cardinality-budget/inventory.tsv 를 만드세요. job="shop-api" 가 내보내는 지표마다 시계열이 몇 개인지를 <지표이름> <시계열 수> 두 칸으로, 많은 순서대로 모두 적습니다(다섯 줄입니다). 파드 전체가 아니라 이 잡 하나로 좁히는 이유는, Prometheus 자신이 내는 지표가 실습 도중에도 계속 늘어나 기준이 흔들리기 때문입니다.
count by (__name__)(last_over_time({job="shop-api"}[1m])) 를 던지면 지표마다 시계열 수가 나옵니다. 히스토그램 하나가 버킷 수만큼 시계열을 만든다는 것이 바로 보일 겁니다.
어느 라벨이 값을 많이 만드는가
/root/obs-cardinality-budget/labels.tsv 를 만드세요. 세 줄이고 각 줄은 <라벨이름> <서로 다른 값의 수> 입니다. le 와 handler 는 히스토그램 지표 http_request_duration_seconds_bucket 에서, status 는 카운터 http_requests_total 에서 셉니다(둘 다 job 은 shop-api). 많은 순서대로 적으세요. 그리고 /root/obs-cardinality-budget/02-note.txt 에 top_label=<1위 라벨 이름> 과 product=<le 값 수 × handler 값 수> 두 줄을 적으세요.
어떤 라벨의 값이 몇 개인지는 count(count by (<라벨>) (...)) 로 셉니다. 지금 살아 있는 시계열만 보려면 last_over_time(<선택자>[1m]) 로 감싸세요 — 그러지 않으면 백필해 둔 과거 시계열까지 함께 세어 값이 흔들립니다. 마지막 곱이 1단계에서 본 히스토그램의 시계열 수와 같아야 합니다.
이 서비스의 지표가 하루에 얼마를 먹는가
/root/obs-cardinality-budget/cost.txt 에 세 줄을 적으세요. series= 는 job="shop-api" 의 시계열 수, samples_per_day= 는 그 시계열이 하루에 남기는 표본 수, bytes_per_day= 는 그 표본이 차지하는 바이트입니다. 이 파드의 스크레이프 간격은 15초이고, 표본 하나는 평균 2바이트로 잡습니다(Prometheus 저장소 문서가 말하는 1바이트에서 2바이트 사이 중 보수적인 쪽). 세 값은 서로 곱셈으로 맞아떨어져야 합니다.
시계열 수는 count(last_over_time({job="shop-api"}[1m])) 입니다. 하루는 86400초이므로 15초 간격이면 시계열당 표본 수가 정해집니다. 이 숫자가 곧 '라벨 하나를 더할 때 늘어나는 비용' 의 단가입니다.
재기 전에 먼저 예측한다
새 지표 checkout_requests_total 을 내보내려 합니다. 라벨은 region(ap1·ap2·us1·eu1), tier(free·pro·team), endpoint(cart·pay·refund·ship·track) 셋입니다. /root/obs-cardinality-budget/forecast.txt 에 formula= 와 predicted_series= 두 줄을 적으세요. formula 는 곱셈식(예: 2*3*4), predicted_series 는 그 결과입니다. 아직 아무것도 띄우지 마세요.
라벨 조합의 수가 곧 시계열의 수입니다. 값이 서로 독립이면 각 라벨의 값 개수를 곱합니다. 예측을 먼저 적어 두는 이유는, 재고 난 뒤에 숫자를 맞추면 무엇을 잘못 생각했는지 알 수 없기 때문입니다.
exporter 를 띄워 예측을 확인한다
/root/obs-cardinality-budget/exporter.py 를 만드세요. 인자로 --print 를 주면 노출 텍스트를 표준 출력에 찍고 끝나고, 인자가 없으면 127.0.0.1:9102 에서 /metrics 를 서비스합니다. 4단계의 세 라벨 조합마다 checkout_requests_total 한 줄을 냅니다. 환경 변수 USERS 가 0 보다 크면 user_id 라벨이 붙습니다. 그다음 /etc/prometheus/prometheus.yml 에 cardinality-lab 이라는 스크레이프 잡을 더하고 설정을 다시 읽히세요. 첫 스크레이프가 끝난 뒤 /root/obs-cardinality-budget/measured.txt 에 measured_series=<수> 한 줄을 적습니다.
서버는 http.server 의 ThreadingHTTPServer 로 충분합니다. 노출 형식은 한 줄에 이름{라벨="값",...} 값 입니다. 설정 반영은 curl -X POST http://127.0.0.1:9090/-/reload 이고, 스크레이프 간격이 15초라 조금 기다려야 합니다. 시계열 수는 count(checkout_requests_total) 로 셉니다.
라벨 하나가 시계열을 백 배로 만든다
USERS=100 으로 exporter 를 다시 띄워 user_id 라벨을 붙이세요. /root/obs-cardinality-budget/explode.tsv 에 두 줄을 적습니다. 각 줄은 탭으로 나눈 세 칸 <이름> <시계열 수> <하루 바이트> 이고, 첫 줄의 이름은 before(user_id 없이), 둘째 줄은 after(user_id 포함)입니다. 하루 바이트는 3단계와 같은 방식(시계열 × 5760 × 2)으로 계산합니다.
시계열 수는 exporter 를 --print 로 돌려 checkout_requests_total 로 시작하는 줄을 세면 바로 나옵니다 — 서버가 떠 있지 않아도 됩니다. 두 줄의 차이가 곧 '라벨 하나의 값'입니다.
상한을 코드로 못박는다
/root/obs-cardinality-budget/budget.sh 를 만드세요. bash budget.sh <상한표> 로 부르면 상한표의 각 줄 (<지표이름> <최대 시계열 수>)마다 지금 시계열 수를 세어 <지표이름> <지금> <상한> OK 또는 ... OVER 를 한 줄씩 출력하고, 하나라도 상한을 넘으면 종료 코드 1, 아니면 0 으로 끝납니다. 그리고 /root/obs-cardinality-budget/caps.tsv 에 checkout_requests_total 의 상한을 500 으로 적고 그 표로 한 번 돌려 출력을 /root/obs-cardinality-budget/gate-out.txt 에 저장하세요.
시계열 수는 count(<지표>) 로 셉니다. 결과가 없으면 0 으로 봐야 합니다 — jq 의 // 로 기본값을 줄 수 있습니다. 종료 코드는 마지막에 한 번만 내야 하므로 변수에 모아 두세요. 채점기는 자기가 만든 상한표 두 개로 이 스크립트를 돌려 통과와 실패를 모두 확인합니다.
예산 안에 들어가려면 무엇을 버릴 것인가
시계열 상한이 500 입니다. /root/obs-cardinality-budget/decision.txt 에 네 줄을 적으세요. keep= 에는 남길 라벨 이름을 쉼표로(예: region,tier), drop= 에는 버릴 라벨 이름을 쉼표로, projected_series= 에는 남긴 라벨만으로 계산한 시계열 수를, lost_question= 에는 그 라벨을 버렸을 때 더 이상 답할 수 없게 되는 질문을 30자 이상으로 적습니다. 라벨의 값 개수는 region 4 · tier 3 · endpoint 5 · user_id 100 입니다.
버릴 라벨을 고르는 기준은 '이 라벨로 무엇을 결정하는가' 입니다. 결정을 바꾸지 않는 라벨은 비쌉니다. 사람 단위 조사는 로그와 추적이 답할 수 있는 질문이라, 지표에서 그 축을 버려도 조사 능력을 통째로 잃지는 않습니다.