Prometheus 고급 가이드 — 메트릭 수집·PromQL·알림·SLO까지
이 글의 핵심
Prometheus에서 고부하 환경의 메트릭을 안정적으로 수집하고, PromQL·Recording Rule로 쿼리 비용을 줄이며, Alertmanager와 연동한 실전 알림·SLO 모니터링까지 한 번에 정리합니다.
이 글의 핵심
Prometheus는 풀(pull) 기반 시계열 저장소로, 마이크로서비스와 쿠버네티스 환경에서 사실상 표준에 가깝습니다. 초기에는 up과 rate()만으로도 운영이 가능하지만, 트래픽과 팀이 커지면 PromQL 최적화, 룰 기반 사전 집계, 서비스 디스커버리, 고가용성·페더레이션, SLO 기반 알림이 핵심 과제가 됩니다.
이 문서는 고급 PromQL, Recording·Alert Rules, Kubernetes·Consul 서비스 디스커버리, Exporter와 커스텀 메트릭, Grafana 대시보드 설계, HA·Federation, 실전 SLO 모니터링을 실무 관점에서 연결해 설명합니다. 각 절마다 왜 필요한지, 어떻게 동작하는지, 운영 시 흔한 실수를 함께 다룹니다.
사전 지식과 범위
다음을 이미 다루어 보았다고 가정합니다.
- Prometheus 기본 개념(타겟, 스크랩, 라벨, 카운터·게이지·히스토그램)
prometheus.yml의scrape_configs구조- Grafana에서 Prometheus를 데이터 소스로 연결
여기서는 운영 규모가 커졌을 때의 설계·쿼리·알림에 초점을 맞춥니다.
PromQL 고급 쿼리
rate와 irate, 그리고 스크랩 간격
카운터의 순간 증가율을 볼 때 rate()는 지정 구간(예: [5m])에서 평균 초당 증가율을 구합니다. 짧은 스파이크는 완만해지고, 알림·대시보드에 안정적인 곡선을 줍니다.
# HTTP 요청 초당 건수 (5분 윈도)
rate(http_requests_total{job="api"}[5m])
irate()는 구간의 마지막 두 샘플만 사용하므로 그래프가 들쭉날쭉하고, 스크랩 지연이나 누락에 민감합니다. 장기 SLO·과금·용량 계획에는 rate()가 일반적으로 적합하고, 디버깅·짧은 구간의 급격한 변화를 볼 때 irate()를 보조적으로 쓰는 패턴이 많습니다.
운영 시 스크랩 간격(scrape_interval)과 rate 윈도 길이를 맞추는 것이 중요합니다. 윈도가 스크랩 간격보다 너무 짧으면 샘플이 부족해 빈 결과나 왜곡이 날 수 있고, 너무 길면 장애 반응이 느려집니다. 팀 내에서 기본 스크랩 간격과 [5m] 같은 표준 윈도를 문서화해 두면 대시보드와 알림이 일관됩니다.
히스토그램과 histogram_quantile
서비스 지연 시간은 히스토그램으로 수집하는 경우가 많습니다. Prometheus는 _bucket, _sum, _count 시계열을 노출합니다.
# API 지연 p99 (히스토그램 버킷 기준, job/path로 좁힘)
histogram_quantile(
0.99,
sum by (le, job) (
rate(http_request_duration_seconds_bucket{job="api"}[5m])
)
)
histogram_quantile은 버킷 경계가 잘 설계되었을 때 의미 있는 분위수를 줍니다. 버킷이 너무 넓거나 샘플이 적으면 실제 꼬리 지연과 다른 값이 나올 수 있습니다. 프로덕션에서는 SLO에 맞춘 상한 버킷(예: 1s, 2s, 5s)과 충분한 요청량을 확보하는 것이 선행 과제입니다.
집계·조인·group_left / group_right
라벨 집합이 다른 시계열을 조인할 때 on(), ignoring()과 함께 그룹 수식이 필요합니다. 한쪽에만 있는 라벨을 붙이려면 group_left를 사용합니다.
# 예: pod_cpu와 pod_memory를 조인해 라벨 병합 (실제 메트릭명은 환경에 맞게 조정)
sum by (pod, namespace) (rate(container_cpu_usage_seconds_total[5m]))
* on (pod, namespace) group_left
sum by (pod, namespace) (container_memory_working_set_bytes)
조인은 카디널리티 폭발과 쿼리 비용을 키우기 쉽습니다. 자주 쓰는 조합은 Recording Rule로 미리 합쳐 두는 것이 운영에 유리합니다.
서브쿼리와 offset, 예측
과거 시점과 비교하거나 추세를 보려면 offset과 [range:resolution] 형태의 서브쿼리를 씁니다.
# 1주 전 대비 에러율 변화 감지 (예시)
(
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
)
-
(
sum(rate(http_requests_total{status=~"5.."}[5m] offset 1w))
/
sum(rate(http_requests_total[5m] offset 1w))
)
predict_linear()는 단기 선형 외삽에 쓰이지만, 트래픽 주기성이 강한 서비스에서는 오탐이 잦을 수 있어 임계값·윈도와 함께 신중히 검증해야 합니다.
Recording Rules와 Alert Rules
Recording Rule: 쿼리 비용과 일관성
동일한 복잡한 표현을 Grafana 패널·알림·레코딩이 반복 참조하면 매번 전 구간을 재계산합니다. Recording Rule은 주기적으로 결과를 새 시계열로 저장해, 대시보드와 알림이 가벼운 시계열만 읽게 합니다.
# recording_rules.yml 예시
groups:
- name: api_recording
interval: 30s
rules:
- record: job:http_requests:rate5m
expr: |
sum by (job) (rate(http_requests_total[5m]))
- record: job:http_errors:ratio5m
expr: |
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total[5m]))
record 이름은 의미 있는 계층(job:metric:aggregation)을 두면 검색과 거버넌스가 쉬워집니다. interval은 스크랩 간격과 정수 배 관계를 맞추는 편이 해석이 단순합니다.
Alert Rule: 표현·라벨·심각도
알림은 측정 가능한 조건과 명확한 라벨이 있어야 온콜이 신뢰합니다. for는 일시적 스파이크를 걸러내지만, 너무 길면 복구까지 알림이 늦게 갑니다.
# alert_rules.yml 예시
groups:
- name: api_alerts
rules:
- alert: HighErrorRate
expr: |
(
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total[5m]))
) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "높은 HTTP 5xx 비율 (job={{ $labels.job }})"
description: "5분 윈도 기준 에러 비율이 5%를 초과했습니다."
알림 메시지에는 $labels와 함께 대시보드 링크·런북을 넣는 것이 좋습니다. Alertmanager에서는 severity, team, service 같은 라벨로 라우팅·억제(inhibit) 정책을 나눕니다.
Service Discovery: Kubernetes와 Consul
Kubernetes
운영 환경에서는 정적 targets 목록 대신 Kubernetes SD가 일반적입니다. Pod·Service·Endpoints 메타데이터를 라벨로 매핑해 타겟을 구성합니다.
# prometheus.yml 발췌 — kubernetes_sd_configs
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
# 어노테이션으로 스크랩 여부 제어
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
relabel_configs는 “무엇을 수집할지”를 거르고, metric_relabel_configs는 “저장할 메트릭을 어떻게 줄일지”에 가깝습니다. 카디널리티가 높은 라벨(사용자 ID, 주문 ID 등)은 드롭하거나 집계 후만 노출하는 편이 안전합니다.
Consul
Consul에 등록된 서비스를 스크랩할 때는 consul_sd_configs로 서비스 이름·태그·메타를 읽고, relabel_configs로 주소·경로를 맞춥니다.
scrape_configs:
- job_name: consul-services
consul_sd_configs:
- server: consul:8500
services: []
relabel_configs:
- source_labels: [__meta_consul_service]
target_label: job
- source_labels: [__meta_consul_tags]
regex: '.*,metrics,.*'
action: keep
Consul 쪽에서는 헬스 체크와 Prometheus 타겟 준비 상태가 어긋나지 않도록, 등록·해제 타이밍을 배포 파이프라인과 맞추는 것이 중요합니다.
Exporters와 커스텀 메트릭
공식·커뮤니티 Exporter
node_exporter(호스트), kube-state-metrics(클러스터 오브젝트 상태), postgres_exporter, redis_exporter 등은 표준 패턴으로 메트릭을 노출합니다. 선택 기준은 관측해야 할 SLO·용량 지표와 운영 부담(스크랩 수, 보안 노출 범위)입니다.
애플리케이션 커스텀 메트릭
서비스 고유 지표는 RED(Rate, Errors, Duration) 또는 USE(Utilization, Saturation, Errors) 틀에 맞추면 대시보드와 알림 설계가 수월합니다.
Go 예시(prometheus/client_golang 개념):
// 개념 예시: 요청 수 카운터, 처리 시간 히스토그램
// 실제 프로젝트에서는 promhttp.Handler()로 /metrics 노출
var (
httpRequests = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests",
},
[]string{"method", "path", "status"},
)
httpDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP latency",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "path"},
)
)
Python(prometheus_client)도 동일하게 Counter·Histogram·Summary를 등록하고, 웹 프레임워크 미들웨어에서 레이블을 일관되게 붙입니다.
커스텀 메트릭에서 흔한 실수는 높은 카디널리티 라벨(요청별 ID)과 히스토그램 버킷 남용입니다. 라벨 설계는 제품·SRE가 합의한 허용 목록으로 제한하는 것이 좋습니다.
Grafana 대시보드 설계
레이어링과 변수
효율적인 대시보드는 글로벌 → 서비스 → 인스턴스 순으로 드릴다운 가능하게 구성합니다.
- 템플릿 변수:
datasource,namespace,job,pod등으로 범위 축소 - 행(Row) 단위: 인프라(노드)·런타임(JVM/Go)·비즈니스(KPI) 구분
- 단위·임계선: p99 지연, 에러율, 포화도에 SLO 기준선 표시
한 화면에 과도한 패널을 넣으면 로딩이 느려지고 인시던트 시 혼란을 줍니다. 인시던트용 요약 대시보드와 원인 분석용 상세 대시보드를 나누는 것이 실무에서 유지보수에 유리합니다.
쿼리 재사용
Grafana에서 PromQL을 복제해 쓰기보다, 가능하면 Recording Rule 시계열을 소스로 삼아 동일 지표 정의를 Prometheus 쪽에 단일화합니다. 그래야 알림·대시보드·기록이 같은 숫자를 가리킵니다.
High Availability와 Federation
이중화의 의미
Prometheus는 단일 바이너리로도 강력하지만, 동일 타겟을 두 서버가 동시에 스크랩하면 중복 시계열이 생기고 집계·알림이 어긋날 수 있습니다. HA를 고려할 때 흔한 패턴은 다음과 같습니다.
- 수평 샤딩: 타겟을 인스턴스별로 나눠 각 Prometheus가 담당
- 리더 선출 또는 활성/대기: 스크랩은 한쪽만
- 장기 저장·글로벌 뷰: Thanos, Cortex/Mimir, VictoriaMetrics 등과 연계
Federation
federation은 상위 Prometheus가 하위의 /federate 엔드포인트에서 선택한 시계열만 당겨오는 방식입니다. 전체 데이터 복제가 아니라 집계된 지표만 올릴 때 적합합니다.
# 상위 prometheus.yml 발췌
scrape_configs:
- job_name: federate-region-a
honor_labels: true
metrics_path: /federate
params:
match[]:
- '{job="api"}'
static_configs:
- targets: ['prometheus-region-a:9090']
페더레이션은 네트워크 비용과 단일 장애점을 고려해 설계해야 하며, 크로스 리전 전체 복제 대신 집계·SLO 지표만 승격하는 편이 안정적입니다.
실전 SLO 모니터링
SLI·SLO·에러 버짓
- SLI(Service Level Indicator): 가용성, 지연, 에러율 등 측정 지표
- SLO(Service Level Objective): 기간 내 달성 목표(예: 월간 가용성 99.9%)
- 에러 버짓(Error budget): 목표 대비 허용 가능한 나쁜 이벤트의 잔량
예를 들어 HTTP 기준으로 성공률 SLI를 다음처럼 정의할 수 있습니다.
# 성공 요청 비율 (5xx 및 타임아웃을 실패로 본다고 가정할 때는 규칙에 맞게 조정)
sum(rate(http_requests_total{status!~"5.."}[30d]))
/
sum(rate(http_requests_total[30d]))
실제 운영에서는 30일 윈도 전체를 매번 계산하면 비용이 크므로, Recording Rule로 일 단위 누적하거나 메타 모니터링 시스템과 병행하는 경우가 많습니다.
번 레이트(Burn rate) 알림
Google SRE 책에서 알려진 패턴으로, 에러 버짓을 비정상적으로 빨리 소진하는지를 감지합니다. 짧은 창과 긴 창을 함께 써 일시적 스파이크와 지속적 악화를 구분합니다.
개념적으로는 다음과 같은 형태입니다(실제 메트릭·SLO 목표는 환경에 맞게 조정).
# 예시: 1시간·30일 기준 번 레이트가 높을 때 (임계값은 튜닝 필요)
groups:
- name: slo_burn
rules:
- alert: ErrorBudgetBurnFast
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[1h]))
/ sum(rate(http_requests_total[1h]))
)
>
14.4 * (1 - 0.999)
for: 5m
labels:
severity: critical
annotations:
summary: "에러 버짓 소진이 빠름 (예시 임계)"
계수 14.4와 0.999는 목표 가용성·페이지 정책에 따라 달라집니다. 중요한 점은 수치를 복사·붙여넣기보다 팀의 SLO 문서와 맞춰 튜닝한다는 것입니다.
운영 체크리스트
- 스크랩·룰 간격·보관 기간이 디스크와 CPU 예산 안인가
- 라벨 카디너리티와 느린 쿼리가 없는가(
prometheus_tsdb_symbol_table_size등 모니터링) - 알림이 행동을 유도하는가(원인·영향·다음 조치)
- HA 시 중복 스크랩·중복 알림이 없는가
- Grafana와 Prometheus의 지표 정의가 한곳에서 관리되는가
정리
Prometheus 고급 운영의 중심은 일관된 라벨·적절한 집계·신뢰할 수 있는 알림입니다. PromQL로 무엇이든 표현할 수 있지만, Recording Rule으로 표준화하고, Kubernetes·Consul SD로 타겟을 자동화하며, SLO·번 레이트로 인시던트 반응을 정렬하면 조직 규모가 커져도 관측 가능성을 유지할 수 있습니다. Grafana는 그 위에서 의사결정에 맞는 시각화를 제공하면 됩니다.