- 들어가며 — 패널은 40개인데 답이 없는 대시보드
- 메트릭이 답할 수 있는 질문의 모양
- 카운터, 게이지, 히스토그램 — 잘못 고르면 계산이 불가능해진다
- 레이블 카디널리티 예산
- rate 가 조용히 틀린 답을 주는 조건
- histogram_quantile 이 조용히 틀린 답을 주는 조건
- 레코딩 룰 — 언제, 어떤 이름으로
- 대시보드에 올리기 전에 스스로 묻는 다섯 개의 질문
- 마치며 — 메트릭의 가치는 개수가 아니라 질문 대응에서 나온다
들어가며 — 패널은 40개인데 답이 없는 대시보드
장애 대응 중에 대시보드를 엽니다. 패널이 40개 있습니다. CPU, 메모리, 스레드 수, GC 횟수, 커넥션 풀 크기, 힙 사용량, 초당 요청 수. 전부 그래프가 그려져 있습니다. 그런데 지금 알고 싶은 것은 하나입니다. "사용자가 실패를 겪고 있는가, 겪고 있다면 몇 퍼센트인가."
그 답이 저 40개 패널 어디에도 없습니다.
메트릭 설계의 문제는 데이터가 부족한 것이 아니라, 수집한 데이터로 답할 수 있는 질문과 답해야 하는 질문이 어긋나 있는 것입니다. 이 글은 그 어긋남을 줄이는 방법을 다룹니다. Prometheus 3.13.0 LTS 기준으로 확인했고, 네이티브 히스토그램은 3.8.0에서 안정화되었지만 스크레이프는 여전히 명시적 옵션으로 켜야 합니다.
메트릭이 답할 수 있는 질문의 모양
메트릭은 시간에 따라 변하는 숫자의 집계입니다. 이 정의에서 답할 수 있는 질문의 모양이 정해집니다.
| 질문 | 메트릭이 답하는가 | 이유 |
|---|---|---|
| 언제부터 나빠졌는가 | 답한다 | 시간축이 연속적이고 과거가 보존됩니다 |
| 몇 퍼센트의 요청이 영향을 받는가 | 답한다 | 집계값이 곧 비율입니다 |
| 어제 같은 시간과 비교해 어떤가 | 답한다 | 저장 비용이 낮아 장기 보존이 됩니다 |
| 이 사용자의 요청이 왜 실패했는가 | 답하지 못한다 | 개별 이벤트가 집계되어 사라졌습니다 |
| 느린 요청이 어느 서비스에서 시간을 썼는가 | 답하지 못한다 | 서비스별 통계는 같은 요청의 것이라는 보장이 없습니다 |
| 어떤 입력값이 이 분기를 태웠는가 | 답하지 못한다 | 값이 레이블에 없으면 복원 불가입니다 |
마지막 세 줄이 중요합니다. 그 질문에 답하려고 레이블을 늘리는 순간 메트릭은 로그나 트레이스의 열등한 대체품이 됩니다. 메트릭의 한계는 카디널리티가 정합니다. 요청마다 값이 달라지는 것을 레이블에 넣기 시작하면, 그것은 이미 메트릭이 아니라 압축률이 나쁜 이벤트 저장소입니다.
시작점은 질문 목록입니다. 온콜이 새벽 3시에 던지는 질문 다섯 개를 먼저 적고, 그 다섯 개에 답하는 메트릭만 만듭니다.
- 사용자가 실패를 겪고 있는가, 몇 퍼센트인가
- 느려졌는가, 어느 라우트가 느려졌는가
- 언제부터인가, 배포와 시각이 겹치는가
- 용량 한계에 닿았는가 (큐 길이, 커넥션 풀, 디스크)
- 의존하는 외부 서비스 중 문제가 있는 곳이 있는가
카운터, 게이지, 히스토그램 — 잘못 고르면 계산이 불가능해진다
타입 선택은 취향이 아닙니다. 잘못 고르면 나중에 하고 싶은 계산이 원리적으로 불가능해집니다.
카운터는 단조 증가만 합니다. 프로세스가 재시작하면 0으로 돌아갑니다. 값 자체는 의미가 없고 rate 로 초당 변화율을 봐야 의미가 생깁니다. 요청 수, 에러 수, 처리한 바이트 수, 재시도 횟수가 여기 해당합니다.
게이지는 오르내립니다. 현재 시점의 상태를 나타냅니다. 큐 길이, 활성 커넥션 수, 메모리 사용량, 온도가 여기 해당합니다.
히스토그램은 관측값의 분포를 버킷 카운터의 집합으로 기록합니다. 지연 시간, 응답 크기처럼 "분위수를 알고 싶은 값"에 씁니다.
가장 흔한 실수는 지연 시간을 게이지로 기록하는 것입니다.
# 나쁨 — 마지막 요청의 지연 시간만 남는다. 분위수도 평균도 계산할 수 없다
from prometheus_client import Gauge
last_latency = Gauge("http_request_duration_seconds", "요청 처리 시간")
def handle(req):
t0 = time.monotonic()
resp = process(req)
last_latency.set(time.monotonic() - t0) # 앞선 값들은 전부 사라진다
return resp
스크레이프 간격이 15초이고 초당 요청이 500건이면, 7500건 중 1건의 값만 저장됩니다. 나머지는 존재한 적도 없는 것이 됩니다. 이 시계열로는 p99를 구할 수 없고, 나중에 데이터를 다시 처리해도 복원되지 않습니다.
# 좋음 — 히스토그램은 모든 관측을 버킷에 누적한다
from prometheus_client import Counter, Histogram
REQUESTS = Counter(
"http_requests_total", "총 요청 수",
["method", "route", "status_class"],
)
LATENCY = Histogram(
"http_request_duration_seconds", "요청 처리 시간",
["method", "route"],
buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
)
def handle(req):
route = req.route_template # "/v1/orders/:id" — 실제 ID 가 아니다
with LATENCY.labels(req.method, route).time():
resp = process(req)
REQUESTS.labels(req.method, route, f"{resp.status // 100}xx").inc()
return resp
status_class 에 주목합니다. 상태 코드를 그대로 넣으면 값이 수십 가지가 되지만, 대부분의 질문은 2xx인지 5xx인지만 필요로 합니다. 세부 코드가 필요한 순간은 조사할 때이고, 그때는 로그를 봅니다.
| 알고 싶은 것 | 타입 | 흔한 오답 | 오답의 결과 |
|---|---|---|---|
| 초당 요청 수 | 카운터 | 게이지로 직전 초의 요청 수 | 스크레이프 사이의 요청이 사라집니다 |
| 지연 시간 분위수 | 히스토그램 | 게이지로 마지막 값 | 분위수 계산 불가 |
| 지연 시간 분위수 | 히스토그램 | 애플리케이션이 계산한 p99 게이지 | 인스턴스 간 집계 불가 |
| 현재 큐 길이 | 게이지 | 카운터로 누적 인큐 수 | 현재 적체를 알 수 없습니다 |
| 총 처리량 | 카운터 | 게이지로 초당 처리량 | 스크레이프 누락 시 그 구간이 소실 |
| 배치 작업 성공 여부 | 카운터 + 타임스탬프 게이지 | 성공 시에만 카운터 증가 | 실패와 미실행을 구분 못 함 |
마지막 줄은 배치 잡에서 반복되는 문제입니다. 실패했을 때도 카운터를 올려야 "돌았는데 실패함"과 "아예 안 돎"을 구분할 수 있습니다. 마지막 성공 시각을 게이지로 남기는 것도 함께 합니다.
JOB_RUNS = Counter("batch_job_runs_total", "배치 실행 횟수", ["job", "result"])
JOB_LAST_SUCCESS = Gauge("batch_job_last_success_timestamp_seconds", "마지막 성공 시각", ["job"])
def run_job(name, fn):
try:
fn()
JOB_RUNS.labels(name, "success").inc()
JOB_LAST_SUCCESS.labels(name).set(time.time())
except Exception:
JOB_RUNS.labels(name, "failure").inc()
raise
레이블 카디널리티 예산
카디널리티는 감이 아니라 곱셈입니다. 메트릭 하나의 시계열 수는 레이블 값 개수의 곱이고, 여기에 인스턴스 수가 곱해집니다.
http_request_duration_seconds_bucket
route 120개 (라우트 템플릿)
method 5개
le 11개 (버킷 경계 + Inf)
instance 40개 (파드 수)
------------------------------------
= 120 * 5 * 11 * 40 = 264,000 시계열
여기에 _sum 과 _count 가 추가된다
120 * 5 * 40 * 2 = 48,000
------------------------------------
합계 약 312,000 시계열 — 메트릭 하나에서
Prometheus 하나가 다루는 활성 시계열은 대략 수백만 개 규모에서 메모리와 쿼리 응답성이 급격히 나빠집니다. 정확한 한계는 하드웨어와 쿼리 패턴에 따라 다르지만, 메트릭 하나가 30만 시계열을 쓴다면 그 하나로 예산의 상당 부분이 사라진다는 점이 중요합니다.
절대 넣으면 안 되는 레이블은 값 집합이 무한에 가까운 것들입니다.
- 사용자 ID, 세션 ID, 요청 ID, 트레이스 ID
- 정규화되지 않은 URL 경로 —
/v1/orders/A-99183 - 이메일, 전화번호, 주문 번호
- 타임스탬프나 그것을 포함한 문자열
- 에러 메시지 원문 — 스택 트레이스 조각이 섞이면 값이 사실상 무한합니다
- 자유 형식 쿼리 문자열
경계선에 있는 것들도 있습니다. pod 이나 instance 는 파드 수만큼 곱해지고, 오토스케일링과 롤링 배포로 값이 계속 바뀌므로 시간이 지날수록 누적됩니다. 인스턴스별 구분이 진짜로 필요한 메트릭에만 남기고, 나머지는 레코딩 룰로 집계한 뒤 원본을 짧게 보존하는 전략이 현실적입니다.
현재 상태를 진단하는 쿼리들입니다.
# 시계열이 가장 많은 메트릭 상위 10개
topk(10, count by (__name__)({__name__=~".+"}))
# 특정 메트릭에서 어떤 레이블이 카디널리티를 만드는가
count(count by (route) (http_requests_total))
count(count by (instance) (http_requests_total))
count(count by (status) (http_requests_total))
# 전체 활성 시계열 추이 — 계단식으로 뛰면 새 레이블이 들어온 것이다
prometheus_tsdb_head_series
# 스크레이프 대상별로 몇 개의 샘플을 주는가 (상한을 넘으면 스크레이프가 거부된다)
topk(20, scrape_samples_scraped)
prometheus_tsdb_head_series 는 알림을 걸어 둘 가치가 있습니다. 카디널리티 사고는 대부분 배포 직후에 계단식으로 나타나므로, 배포와 시각을 맞춰 보면 원인 커밋을 바로 찾을 수 있습니다.
수집 시점에서 막는 방법도 있습니다. 스크레이프 설정에 샘플 수 상한을 걸면, 폭발한 대상이 Prometheus 전체를 무너뜨리는 것을 막습니다.
# prometheus.yml
scrape_configs:
- job_name: checkout-api
sample_limit: 20000 # 이 대상이 이보다 많이 주면 스크레이프 실패로 처리
label_limit: 24
label_value_length_limit: 256
scrape_interval: 15s
metric_relabel_configs:
# 사고 대응용 — 문제가 된 레이블을 수집 시점에 지운다.
# labeldrop 이 아니라 replace 로 빈 값을 넣는 이유: labeldrop 은
# 레이블 "이름"만 보고 매칭해서 이 job 의 모든 메트릭에서 user_id 를
# 지운다. 아래처럼 쓰면 http_requests_total 에서만 지울 수 있다.
# 빈 값 레이블은 Prometheus 데이터 모델에서 없는 레이블과 같다.
- source_labels: [__name__]
regex: 'http_requests_total'
target_label: user_id
replacement: ''
action: replace
# 아예 필요 없는 메트릭은 버린다
- source_labels: [__name__]
regex: 'go_gc_duration_seconds.*|python_gc_.*'
action: drop
sample_limit 이 걸리면 그 대상의 스크레이프가 통째로 실패하므로, 값은 넉넉하게 잡되 반드시 걸어 둡니다. 상한이 없으면 한 서비스의 실수가 전체 모니터링을 중단시킵니다.
rate 가 조용히 틀린 답을 주는 조건
rate 는 range vector의 첫 샘플과 마지막 샘플로 초당 증가율을 구하고, 카운터 리셋을 보정합니다. 함정은 세 가지입니다.
함정 1 — 윈도우가 스크레이프 간격에 비해 좁다
rate 는 윈도우 안에 최소 두 개의 샘플이 필요합니다. 스크레이프 간격이 15초인데 윈도우가 20초면, 샘플이 하나만 들어오는 순간이 생겨 결과가 비어 버립니다. 그래프에는 구멍으로, 알림에서는 "조건이 성립하지 않음"으로 나타납니다.
# 위험 — 스크레이프 간격이 15s 일 때 [20s] 는 샘플이 1개인 순간이 생긴다
rate(http_requests_total[20s])
# 안전 — 스크레이프 간격의 4배 이상. 알림에는 [5m] 이상을 권한다
rate(http_requests_total[1m])
rate(http_requests_total[5m])
경험칙은 간단합니다. 알림에는 5분 이상, 대시보드에는 Grafana의 rate 간격 변수를 씁니다. 4배 규칙은 스크레이프 한두 번이 누락돼도 결과가 살아남게 합니다.
함정 2 — rate 를 sum 뒤에 적용한다
이 실수는 결과가 그럴듯해서 오래 살아남습니다.
# 틀림 — 카운터를 먼저 더하면 인스턴스 재시작(리셋)이 감지되지 않는다
rate(sum(http_requests_total) by (route)[5m:])
# 맞음 — rate 를 먼저, 집계는 그다음
sum(rate(http_requests_total[5m])) by (route)
카운터 리셋 보정은 개별 시계열 단위로만 정확합니다. 파드 하나가 재시작하면 그 시계열은 0으로 떨어지는데, 이미 합산된 뒤에는 "전체가 조금 줄었다"로만 보여서 리셋으로 인식되지 않습니다. 결과는 실제보다 낮게 나온 요청률이고, 배포 직후마다 트래픽이 줄어든 것처럼 보입니다.
함정 3 — 카운터를 그대로 그린다
# 그래프가 계속 우상향하는 직선이 나온다. 아무 정보도 없다
http_requests_total
# 초당 증가율 — 이것이 보고 싶었던 값이다
sum(rate(http_requests_total[5m])) by (route)
# 특정 구간의 총 증가량 — 알림 문구에 쓰기 좋다
sum(increase(http_requests_total{status_class="5xx"}[1h])) by (route)
increase 는 rate 에 윈도우 길이를 곱한 것입니다. 따라서 정수가 아닌 값이 나옵니다. 에러가 3건 발생했는데 increase 가 3.4를 반환하는 것은 버그가 아니라 외삽의 결과입니다. "정확히 N건"이 필요한 계산에는 쓰지 않습니다.
irate 는 마지막 두 샘플만 봅니다. 대시보드에서 순간 반응을 볼 때는 쓸모가 있지만 알림에는 절대 쓰지 않습니다. 노이즈 한 번에 발화합니다.
histogram_quantile 이 조용히 틀린 답을 주는 조건
분위수 계산은 함정이 더 많습니다.
함정 1 — le 를 집계에서 빼먹는다
# 틀림 — le 를 버리면 버킷이 뭉개져서 의미 없는 숫자가 나온다
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (route))
# 맞음 — le 는 반드시 남긴다
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, route)
)
이 실수는 에러를 내지 않고 숫자를 반환합니다. 그래서 대시보드에 몇 달씩 남아 있습니다.
함정 2 — 버킷 경계 밖에서 추정한다
histogram_quantile 은 버킷 사이를 선형 보간합니다. p99가 마지막 유한 버킷보다 위에 있으면 함수는 그 마지막 경계값을 반환합니다. 실제 p99가 8초인데 마지막 버킷이 2.5초라면 결과는 영원히 2.5초입니다.
# 진단 — Inf 버킷과 마지막 유한 버킷의 비율을 본다
sum(rate(http_request_duration_seconds_bucket{le="+Inf"}[5m])) by (route)
-
sum(rate(http_request_duration_seconds_bucket{le="10.0"}[5m])) by (route)
이 값이 0보다 크면 마지막 버킷을 넘는 요청이 있다는 뜻이고, p99가 신뢰할 수 없는 상태일 수 있습니다.
반대로 버킷이 너무 성기면 보간 오차가 큽니다. 버킷이 0.1과 1.0뿐인데 요청 대부분이 0.15초에 몰려 있으면, p99 추정은 0.1과 1.0 사이를 선형으로 자르므로 실제와 크게 어긋납니다. 버킷은 SLO 임계값 주변을 촘촘하게 잡습니다. 300ms를 목표로 한다면 0.2, 0.25, 0.3, 0.4, 0.5가 버킷에 있어야 합니다.
함정 3 — 분위수를 평균 낸다
# 틀림 — 분위수는 산술 평균이 성립하지 않는다
avg(histogram_quantile(0.99, ...))
# 맞음 — 버킷 카운터를 먼저 합치고 나서 분위수를 구한다
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
인스턴스별 p99의 평균은 전체 p99가 아닙니다. 히스토그램이 가치 있는 이유가 정확히 이것입니다. 버킷 카운터는 더할 수 있고, 더한 뒤에 분위수를 구하면 전체 분포에 대한 추정이 됩니다. 애플리케이션이 자체 계산한 p99 게이지를 노출하면 이 성질을 잃습니다.
네이티브 히스토그램
Prometheus 3.8.0부터 네이티브 히스토그램이 안정 기능입니다. 버킷 경계를 지수 스키마로 자동 관리하므로 경계를 직접 고를 필요가 없고, 하나의 시계열로 표현되어 카디널리티가 크게 줄어듭니다. 다만 스크레이프는 명시적으로 켜야 합니다.
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: checkout-api
# 네이티브 히스토그램 스크레이프는 명시적 opt-in
scrape_native_histograms: true
static_configs:
- targets: ['checkout-api:8000']
# 고정 버킷: _bucket 시계열에 le 레이블
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, route))
# 네이티브 히스토그램: le 없이 메트릭 자체를 넘긴다
histogram_quantile(0.99, sum(rate(http_request_duration_seconds[5m])) by (route))
| 항목 | 고정 버킷 히스토그램 | 네이티브 히스토그램 |
|---|---|---|
| 시계열 수 | 버킷 수 곱하기 레이블 조합 | 레이블 조합당 1개 |
| 버킷 설계 | 미리 골라야 하고 바꾸면 과거와 불연속 | 자동, 해상도만 지정 |
| 범위 밖 값 | 마지막 경계에서 잘림 | 지수 스키마로 넓게 커버 |
| 도구 호환성 | 어디서나 동작 | 스크레이프 opt-in 필요, 일부 도구 미지원 |
| 이관 난이도 | 기준선 | 쿼리와 대시보드 수정 필요 |
전환은 신규 메트릭부터 하는 편이 안전합니다. 기존 메트릭을 바꾸면 그 시점에 과거 데이터와 쿼리가 불연속이 됩니다.
레코딩 룰 — 언제, 어떤 이름으로
레코딩 룰은 계산을 쿼리 시점에서 평가 시점으로 옮깁니다. 만들 기준은 넷입니다.
- 같은 표현식이 세 곳 이상에서 반복될 때
- 쿼리 실행이 2초를 넘을 때
- 알림 규칙이 무거운 표현식을 매 평가마다 돌릴 때
- 고카디널리티 원본을 집계해서 장기 보존하고 싶을 때
이름은 수준:메트릭:연산 규약을 따릅니다. 콜론은 레코딩 룰에만 쓰고 원본 메트릭 이름에는 절대 쓰지 않습니다. 이 규약을 지키면 이름만 보고 무엇이 남아 있는 차원인지 알 수 있습니다.
# rules/http.yml
groups:
- name: http_sli
interval: 30s
rules:
# 계층 1 — 원본에서 한 번만 집계한다
- record: route:http_requests:rate5m
expr: sum(rate(http_requests_total[5m])) by (route)
- record: route:http_requests_errors:rate5m
expr: sum(rate(http_requests_total{status_class="5xx"}[5m])) by (route)
# 계층 2 — 계층 1 을 참조한다. 원본을 다시 스캔하지 않는다
- record: route:http_error_ratio:rate5m
expr: |
route:http_requests_errors:rate5m
/
route:http_requests:rate5m
- record: route:http_request_duration_seconds:p99_rate5m
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, route)
)
# 서비스 전체 — 라우트 차원을 없앤 요약
- record: service:http_error_ratio:rate5m
expr: |
sum(rate(http_requests_total{status_class="5xx"}[5m]))
/
sum(rate(http_requests_total[5m]))
계층 구조가 핵심입니다. 계층 1을 여러 규칙이 재사용하면 원본 시계열 스캔이 한 번으로 끝납니다. 다만 규칙끼리 순환 참조를 만들면 안 되고, promtool 이 이것을 잡아 주지 못하므로 리뷰에서 확인해야 합니다.
레코딩 룰이 만드는 시계열 수는 배포 전에 계산합니다. 라우트가 120개인데 5개 윈도우에 대해 각각 규칙을 만들면 600개의 새 시계열입니다. 규칙이 50개면 3만 개입니다.
검증은 CI에서 돌립니다.
# 문법 검사
promtool check rules rules/http.yml
# 단위 테스트 — 입력 시계열을 주고 기대값을 검증한다
promtool test rules tests/http_test.yml
# 전체 설정 검사
promtool check config prometheus.yml
# tests/http_test.yml
rule_files:
- ../rules/http.yml
evaluation_interval: 30s
tests:
- interval: 15s
input_series:
- series: 'http_requests_total{route="/v1/orders", status_class="2xx"}'
values: '0+150x40'
- series: 'http_requests_total{route="/v1/orders", status_class="5xx"}'
values: '0+3x40'
promql_expr_test:
- expr: route:http_error_ratio:rate5m
eval_time: 8m
exp_samples:
- labels: 'route:http_error_ratio:rate5m{route="/v1/orders"}'
value: 0.0196078431372549
기대값을 직접 계산해 두면, 나중에 누군가 규칙을 "최적화"하다가 의미를 바꿨을 때 CI가 잡아냅니다.
대시보드에 올리기 전에 스스로 묻는 다섯 개의 질문
패널을 하나 만들 때마다 아래를 통과시킵니다. 통과하지 못하면 그 패널은 만들지 않습니다.
- 이 패널이 답하는 질문을 한 문장으로 쓸 수 있는가. "CPU 사용률"은 질문이 아닙니다. "이 서비스가 CPU 한계에 닿아서 지연이 생기고 있는가"가 질문입니다.
- 값이 나빠졌을 때 무엇을 할지 정해져 있는가. 볼 수는 있지만 아무 행동도 유발하지 않는 지표는 대시보드가 아니라 탐색 쿼리로 남깁니다.
- 이 값이 사용자 경험과 어떻게 연결되는가. GC 횟수는 그 자체로는 아무 의미가 없습니다. 지연 시간과 함께 놓여야 의미가 생깁니다.
- 정상 범위를 아는가. 정상이 무엇인지 모르면 이상도 알 수 없습니다. 축의 범위와 임계선을 함께 정합니다.
- 이 쿼리가 카운터를 그대로 그리거나 분위수를 평균 내고 있지 않은가. 앞의 두 절에서 다룬 함정을 한 번 더 확인합니다.
패널 순서도 질문 순서를 따릅니다. 맨 위는 사용자 관점 지표, 그 아래가 원인 후보, 맨 아래가 인프라 자원입니다. 위에서 아래로 읽으면 "영향이 있는가, 어디서 오는가, 자원 문제인가"의 흐름이 됩니다.
마치며 — 메트릭의 가치는 개수가 아니라 질문 대응에서 나온다
메트릭 300개짜리 시스템에서 온콜이 답을 못 찾는 일은 흔합니다. 반대로 잘 고른 20개로 대부분의 장애를 좁혀 나가는 팀도 있습니다. 차이는 수집량이 아니라, 각 메트릭이 어떤 질문에 답하려고 존재하는지가 명시되어 있느냐입니다.
지금 할 수 있는 가장 값싼 점검은 두 가지입니다. 첫째, 시계열 수 상위 10개 메트릭을 뽑아 각각 "이걸로 어떤 질문에 답하는가"를 적어 봅니다. 답이 안 나오는 것이 대개 비용의 절반을 차지합니다. 둘째, 대시보드에서 histogram_quantile 이 들어간 쿼리를 전부 검색해 by (le 가 있는지 확인합니다. 하나쯤은 빠져 있습니다.
더 파고들 자료입니다.
현재 단락 (1/229)
장애 대응 중에 대시보드를 엽니다. 패널이 40개 있습니다. CPU, 메모리, 스레드 수, GC 횟수, 커넥션 풀 크기, 힙 사용량, 초당 요청 수. 전부 그래프가 그려져 있습니다...