LabHub

블로그

Prometheus PromQL 마스터 가이드

한국어English日本語

PromQL Mastery Guide

1. PromQL 기본 개념

PromQL(Prometheus Query Language)은 Prometheus의 시계열 데이터를 조회하고 분석하는 쿼리 언어입니다. Grafana 대시보드, 알림 규칙 모두 PromQL로 작성합니다.

4가지 데이터 타입

타입설명예시
Instant Vector동일 타임스탬프의 시계열 집합http_requests_total
Range Vector시간 범위의 시계열http_requests_total[5m]
Scalar단일 숫자 값3.14
String문자열 (거의 안 씀)"hello"

메트릭 타입

Counter  — 단조 증가 값 (리셋 시 0으로) : http_requests_total
Gauge    — 올라갈 수도 내려갈 수도 : temperature, memory_usage
Histogram — 분포 측정 (bucket) : http_request_duration_seconds
Summary  — 분위수 직접 계산 : go_gc_duration_seconds

2. 셀렉터와 매칭

# 기본 셀렉터
http_requests_total

# 라벨 매칭
http_requests_total{method="GET", status="200"}

# 정규식 매칭
http_requests_total{method=~"GET|POST"}
http_requests_total{status!~"2.."}

# 부정 매칭
http_requests_total{method!="DELETE"}

# __name__ 매칭 (메트릭 이름도 라벨)
{__name__=~"http_requests.*"}

3. 핵심 함수

rate() — Counter의 초당 변화율

# 지난 5분간 초당 요청 수
rate(http_requests_total[5m])

# job별 초당 요청 수
sum(rate(http_requests_total[5m])) by (job)

# method별 초당 요청 수 Top 5
topk(5, sum(rate(http_requests_total[5m])) by (method))

주의: rate()는 반드시 Counter 타입에만 사용하세요. Gauge에는 deriv()를 사용합니다.

increase() — 일정 시간 동안의 증가량

# 지난 1시간 동안의 총 요청 수
increase(http_requests_total[1h])

# 일일 에러 수
sum(increase(http_requests_total{status=~"5.."}[24h]))

histogram_quantile() — 퍼센타일 계산

# 95th 퍼센타일 응답 시간
histogram_quantile(0.95,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)

# 서비스별 99th 퍼센타일
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
)

# 50th (중앙값) 응답 시간
histogram_quantile(0.5,
  rate(http_request_duration_seconds_bucket[5m])
)

irate() — 순간 변화율

# 최근 2개 데이터 포인트 기준 순간 변화율
irate(http_requests_total[5m])

rate()는 전체 범위의 평균, irate()는 가장 최근 2개 포인트의 변화율입니다. 대시보드에서는 irate()가 더 반응적이고, 알림에는 rate()가 더 안정적입니다.

4. 집계 연산자

# sum — 합계
sum(rate(http_requests_total[5m])) by (instance)

# avg — 평균
avg(node_cpu_seconds_total{mode="idle"}) by (instance)

# max, min
max(container_memory_usage_bytes) by (pod)

# count — 시계열 개수
count(up == 1) by (job)

# quantile — 분위수
quantile(0.95, rate(http_requests_total[5m]))

# stddev — 표준편차
stddev(rate(http_requests_total[5m])) by (job)

# without — 특정 라벨 제외하고 집계
sum without (instance)(rate(http_requests_total[5m]))

5. 실전 쿼리 패턴

에러율 계산

# HTTP 5xx 에러율 (%)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
* 100

# 서비스별 가용률
1 - (
  sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
  /
  sum(rate(http_requests_total[5m])) by (service)
)

리소스 사용률

# CPU 사용률 (%)
100 - (avg by (instance)(
  irate(node_cpu_seconds_total{mode="idle"}[5m])
) * 100)

# 메모리 사용률 (%)
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

# 디스크 사용률
(1 - node_filesystem_avail_bytes{mountpoint="/"}
  / node_filesystem_size_bytes{mountpoint="/"}) * 100

Saturation (포화도)

# Pod CPU throttling
sum(rate(container_cpu_cfs_throttled_seconds_total[5m])) by (pod)
/
sum(rate(container_cpu_cfs_periods_total[5m])) by (pod)

# 큐 길이
avg_over_time(queue_length[5m])

6. 알림 규칙 작성

# prometheus-rules.yaml
groups:
  - name: application
    rules:
      # 높은 에러율
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
          /
          sum(rate(http_requests_total[5m])) by (service)
          > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: 'High error rate on {{ $labels.service }}'
          description: 'Error rate is {{ $value | humanizePercentage }}'

      # 느린 응답 시간
      - alert: SlowResponseTime
        expr: |
          histogram_quantile(0.95,
            sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
          ) > 1.0
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'P95 latency > 1s on {{ $labels.service }}'

  - name: infrastructure
    rules:
      # 높은 메모리 사용률
      - alert: HighMemoryUsage
        expr: |
          (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9
        for: 15m
        labels:
          severity: warning

      # 디스크 부족 예측
      - alert: DiskWillFillIn24h
        expr: |
          predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600) < 0
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: 'Disk will fill in 24h on {{ $labels.instance }}'

      # Pod CrashLooping
      - alert: PodCrashLooping
        expr: |
          increase(kube_pod_container_status_restarts_total[1h]) > 5
        for: 10m
        labels:
          severity: critical

7. Grafana 대시보드 쿼리

# RED Method 대시보드

# Rate (요청 수/초)
sum(rate(http_requests_total[5m])) by (service)

# Errors (에러 수/초)
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)

# Duration (지연 시간 분포)
histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket[$__rate_interval])) by (le))
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[$__rate_interval])) by (le))
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[$__rate_interval])) by (le))

8. 퀴즈

Q1: rate()와 irate()의 차이점과 각각 적합한 사용 상황은?

rate(): 전체 범위의 초당 평균 변화율을 계산합니다. 더 부드럽고 안정적이어서 알림 규칙에 적합합니다. irate(): 범위 내 가장 최근 2개 데이터 포인트의 순간 변화율입니다. 스파이크를 빠르게 감지하므로 대시보드 그래프에 적합합니다.

주의: 둘 다 Range Vector를 인자로 받지만 [5m]의 의미가 다릅니다. rate()는 5분 평균, irate()는 5분 내 최근 2포인트만 사용합니다.

Q2: predict_linear() 함수의 용도와 동작 원리는?

predict_linear(v range-vector, t scalar)는 시계열 데이터에 선형 회귀를 적용하여 t초 후의 값을 예측합니다.

예: predict_linear(node_filesystem_avail_bytes[6h], 24*3600) < 0 → 지난 6시간의 디스크 여유 공간 추세를 분석하여 24시간 후 0 이하가 될지 예측합니다.

디스크 부족, 메모리 증가 등 자원 고갈을 미리 감지하는 용량 계획 알림에 핵심적으로 사용됩니다.

Q3: histogram_quantile에서 le 라벨의 역할과 주의사항은?

le는 "less than or equal"의 약자로, 히스토그램 버킷의 상한값을 나타냅니다. http_request_duration_seconds_bucket{le="0.5"}는 0.5초 이하인 요청 수입니다.

주의사항:

by (le)를 반드시 포함해야 합니다 — 빠뜨리면 le별 집계가 깨져서 잘못된 값이 나옵니다 버킷 경계가 적으면 보간(interpolation)이 부정확합니다 결과는 근사치입니다 — 정확한 퍼센타일이 필요하면 Summary 타입을 사용하세요

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다