← Posts

Observability · Metrics · Histogram

메트릭 - 지금 시스템이 어떤가

메트릭은 시간에 따른 수다. 카운터·게이지·히스토그램 세 유형, 라벨이 비용이 되는 카디널리티 함정, 그리고 평균이 아니라 분포로 봐야 하는 이유까지.

목차
  1. 로그를 세면 수가 된다
  2. 세 가지 유형: 카운터·게이지·히스토그램
  3. 라벨로 쪼개 본다
  4. 카디널리티: 라벨이 비용이다
  5. 평균이 아니라 분포로 본다
  6. 무엇을 재나: RED와 USE
  7. 메트릭은 왜인지를 모른다
  8. 실무에서: 시계열 DB와 대시보드
  9. 정리

로그가 “사건 하나”라면 메트릭은 “그 사건들을 세어 요약한 수”다. 전체 상태를 한눈에 보려면 개별 기록이 아니라 집계가 필요하다.

로그를 세면 수가 된다

메트릭시간에 따라 변하는 수다. 로그가 “14:03:15에 결제가 실패했다”는 사건이라면, 메트릭은 “이번 1분간 결제 실패 12건”이라는 집계된 수다.

plaintext
14:03  요청 1,200건  에러 8건  응답 중앙값 40ms
14:04  요청 1,350건  에러 47건 응답 중앙값 210ms   ← 무언가 나빠졌다

개별 요청은 안 보이지만, 전체가 지금 어떤지가 한눈에 온다. 초당 수천 건을 로그로 세는 건 불가능하지만, 메트릭은 애초에 세어둔 수라 즉시 답한다.

세 가지 유형: 카운터·게이지·히스토그램

메트릭은 재는 대상에 따라 세 종류다.

  • 카운터(counter) - 늘기만 하는 수. 총 요청 수, 총 에러 수. “얼마나 많이 일어났나.”
  • 게이지(gauge) - 오르내리는 수. 현재 메모리 사용량, 활성 연결 수, 대기 중인 스레드. “지금 이 순간 얼마인가.”
  • 히스토그램(histogram) - 분포. 응답 시간이 010ms에 몇 건, 10100ms에 몇 건… 버킷마다 센다. “값들이 어떻게 퍼져 있나.”

셋을 헷갈리면 엉뚱한 걸 잰다 - 응답 시간을 게이지로 “현재 40ms”라고만 두면, 느린 요청이 섞여도 안 보인다. 응답 시간은 분포라서 히스토그램이 맞다. 왜 그런지가 뒤에 나온다.

라벨로 쪼개 본다

수 하나로는 “어디가” 나쁜지 모른다. 그래서 메트릭에 라벨(차원)을 붙여 쪼갠다.

plaintext
요청 수  method=GET  status=200  →  1,180
요청 수  method=POST status=500  →  47      ← POST가 터지고 있다

method·status·endpoint별로 나눠 보면, “에러 47건”이 뭉뚱그린 수가 아니라 **“결제 POST에서 500이 난다”**로 좁혀진다. 라벨이 메트릭을 쓸모 있게 만든다.

카디널리티: 라벨이 비용이다

그런데 라벨에는 함정이 있다. 라벨 값의 조합 하나하나가 별도의 시계열로 저장된다. 이 조합의 수를 카디널리티라 한다.

method(5가지) × status(6가지) × endpoint(20가지) = 600개. 여기까진 괜찮다. 그런데 user_id를 라벨로 붙이면?

plaintext
사용자 100만 명 × 나머지 조합 = 시계열 수억 개

메모리도 비용도 폭발한다. 카디널리티가 높은 값(사용자ID·요청ID·이메일)은 라벨로 쓰면 안 된다 - 그런 “누구였나”는 로그나 트레이스가 맡고, 메트릭은 낮은 카디널리티의 집계에만 쓴다. 초중급이 메트릭에서 제일 자주 밟는 지뢰다.

평균이 아니라 분포로 본다

응답 시간을 평균으로 보면 병목이 숨는다. 100건 중 95건이 10ms고 5건이 10초면 평균은 510ms인데, 이 값은 아무도 겪지 않은 수다. 전원이 조금 느렸는지, 5%가 완전히 멈췄는지 평균은 구별하지 못한다.

그래서 백분위로 본다 - p95, p99는 “느린 쪽 꼬리”를 드러낸다. 이 “평균의 거짓말”과 백분위를 왜 그렇게 읽는지는 병목 글에서 정면으로 다룬다. 여기서 이을 지점은 하나 - 히스토그램이 바로 그 백분위를 준다. 값의 분포를 버킷으로 세어두니, “p99 = 몇 ms”를 뽑아낼 수 있다(정확한 값이 아니라 버킷 기반 근사지만, 실무엔 충분하다). 응답 시간을 히스토그램으로 재는 이유다.

무엇을 재나: RED와 USE

“막상 뭘 재야 하지?”가 막막할 때 쓰는 체크리스트가 둘 있다.

  • RED - 요청을 받는 서비스에. Rate(초당 요청), Errors(실패율), Duration(응답 시간). “사용자가 겪는 것.”
  • USE - 자원(CPU·디스크·메모리)에. Utilization(사용률), Saturation(대기·포화), Errors(오류). “자원이 버티나.”

둘을 합치면 “사용자가 아픈가(RED)“와 “어느 자원이 조이나(USE)“를 나눠 볼 수 있다. 처음엔 이 몇 개만 제대로 재도 대부분의 사고가 보인다.

메트릭은 왜인지를 모른다

메트릭은 강력하지만 한계가 분명하다. “결제 500 에러율이 5%로 올랐다”는 알려주지만, 그게 왜인지, 정확히 어떤 요청이었는지는 모른다. 집계된 수라서, 개별 사건의 사연은 이미 뭉개졌다.

그래서 메트릭은 “이상하다”를 가장 먼저 알리는 신호이되, 거기서 멈춘다. “왜”로 넘어가려면 그 요청의 로그를, “어디서”로 넘어가려면 트레이스를 봐야 한다.

실무에서: 시계열 DB와 대시보드

  • 메트릭은 시계열 데이터베이스에 저장하고(Prometheus류) 대시보드로 본다.
  • 보관 비용 때문에 오래된 데이터는 잘게 안 두고 뭉쳐서 요약한다 - 최근 건 초 단위, 지난달 건 시간 단위로.
  • 알림은 메트릭에 건다 - 백분위·에러율이 선을 넘으면 사람을 부른다(헬스체크와 알림 편에서).

정리

  • 메트릭은 시간에 따른 집계된 수 - 로그가 못 하는 “지금 전체가 어떤가”에 답한다.
  • 세 유형: 카운터(늘기만)·게이지(오르내림)·히스토그램(분포). 응답 시간은 분포라 히스토그램.
  • 라벨로 쪼개 보되, 사용자ID처럼 카디널리티 높은 값은 라벨 금지 - 시계열이 폭발한다.
  • 평균은 거짓말을 하니 **분포(백분위)**로 본다. 단 메트릭은 왜인지는 모른다 - 그건 트레이스·로그의 몫이다.

다음 글은 한 요청이 서비스들을 지나며 어디서 느렸는지를 따라가는 분산 트레이싱으로 간다.

관련 글