LLM WikiAccess-protected knowledge portal
← 스터디 홈
2편 · 약 17분

PromQL과 알림 규칙

PromQL이 필요한 이유

Prometheus가 수집한 시계열 데이터는 그 자체로는 숫자 더미다. 의미를 만들려면 쿼리가 필요하다. PromQL은 레이블을 기준으로 수천 개의 시계열을 한 번에 집계하고, 변화율을 계산하고, 퍼센타일을 추정할 수 있게 설계된 전용 언어다. SQL과 달리 테이블 조인이 없고, 시계열 연산에 특화된 함수들이 중심이다.

네 가지 데이터 타입

PromQL 표현식의 반환 타입은 네 가지다.

타입설명예시
Instant vector각 레이블 집합의 최신 샘플 한 개씩http_requests_total
Range vector특정 기간 동안의 샘플 이력http_requests_total[5m]
Scalar단일 부동 소수점 숫자1.5
String문자열 (거의 쓰이지 않음)"hello"

Instant vector는 지금 이 순간 각 레이블 집합에 대해 가장 최근 샘플을 하나씩 반환한다. 대부분의 집계 함수가 Instant vector를 입력으로 받는다.

Range vector는 특정 기간의 샘플 이력을 담는다. [5m]은 "현재 기준 5분 이내의 샘플들"을 의미한다. rate() 같은 변화율 함수는 반드시 Range vector를 입력으로 받는다.

셀렉터와 매처

중괄호 안에 레이블 매처를 써서 원하는 시계열만 선택한다.

http_requests_total{job="api-server"}          -- 완전 일치
http_requests_total{status!="200"}             -- 제외
http_requests_total{method=~"GET|POST"}        -- 정규식 일치
http_requests_total{method!~"GET|POST"}        -- 정규식 제외

매처 없이 메트릭 이름만 쓰면 그 이름을 가진 모든 시계열이 선택된다. 카디널리티가 높은 메트릭에서 매처 없이 쿼리하면 부하가 커진다.

rate와 irate: Counter를 의미 있게 만드는 함수

Counter는 값이 단조 증가하므로 현재 절댓값 자체는 별 의미가 없다. rate()로 초당 평균 변화율을 구해야 의미 있는 수치가 된다.

rate(http_requests_total[5m])

이 쿼리는 "최근 5분 동안의 HTTP 요청 초당 평균 수"를 돌려준다. 범위가 넓을수록 값이 평탄해지고 일시 스파이크가 희석된다.

irate()는 범위 벡터 안의 마지막 두 샘플만 보고 순간 변화율을 계산한다. 스파이크를 잡는 데 유리하지만 노이즈가 많다. 알림 규칙보다는 대시보드에서 실시간 트렌드를 볼 때 더 적합하다.

irate(http_requests_total[5m])   -- 5m은 샘플 탐색 범위, 계산은 마지막 두 점

increase()는 rate의 변형으로, 범위 동안의 증가 절댓값을 돌려준다.

increase(http_requests_total[1h])  -- 지난 1시간 동안 총 증가 요청 수

집계 연산자

Instant vector를 레이블 기준으로 집계한다.

sum(rate(http_requests_total[5m]))                          -- 전체 합계
sum by (job)(rate(http_requests_total[5m]))                 -- job 레이블별 합계
sum without (instance)(rate(http_requests_total[5m]))       -- instance만 제거 후 합계

by는 "이 레이블들만 남기고 집계", without은 "이 레이블들만 제거하고 집계"다. 자주 쓰는 집계 연산자는 sum, avg, max, min, count, topk, bottomk다.

topk(5, rate(http_requests_total[5m]))처럼 상위 N개를 고르는 것도 자주 쓰인다.

histogram_quantile: 퍼센타일 계산

Histogram 타입 메트릭에서 p99 지연 시간처럼 퍼센타일을 구할 때 쓴다.

histogram_quantile(
  0.99,
  sum by (le)(rate(http_request_duration_seconds_bucket[5m]))
)

이 쿼리의 의미는 "최근 5분 동안의 HTTP 요청 중 99%가 응답한 시간 이하인 값"이다. 0.5이면 p50(중앙값), 0.95이면 p95다.

중요한 제약이 있다. histogram_quantile은 수학적 추정이다. Histogram의 bucket 경계와 실제 데이터 분포가 다르면 오차가 생긴다. 그래도 Summary보다 유연한 이유는 여러 인스턴스의 bucket을 서버에서 합산한 뒤 퍼센타일을 계산할 수 있기 때문이다.

Recording Rules: 반복 쿼리를 미리 저장

대시보드나 알림 규칙에 같은 복잡한 쿼리가 반복 등장하면 Prometheus가 매번 계산해야 한다. Recording rules는 그 결과를 새 시계열로 미리 저장해 둔다.

groups:
  - name: http_aggregations
    interval: 1m
    rules:
      - record: job:http_requests:rate5m
        expr: sum by (job)(rate(http_requests_total[5m]))

이 규칙은 1분마다 평가되며 결과를 job:http_requests:rate5m이라는 새 메트릭으로 저장한다. 이후 대시보드는 복잡한 원본 쿼리 대신 이 메트릭만 조회한다.

Recording rule 이름 관례는 level:metric:operations 형식이다. 위 예시에서 job이 level, http_requests가 metric, rate5m이 operation이다. 일관된 이름은 대시보드 쿼리를 단순하게 유지해 주고, 나중에 원본 메트릭이 바뀌어도 대시보드 쿼리를 건드리지 않아도 된다.

Alerting Rules: 조건과 상태 전이

알림 규칙은 PromQL 표현식이 참인 동안 알림을 발생시킨다.

groups:
  - name: api_alerts
    rules:
      - alert: HighErrorRate
        expr: >
          rate(http_requests_total{status=~"5.."}[5m])
          /
          rate(http_requests_total[5m])
          > 0.05
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "High error rate on {{ $labels.job }}"
          description: "Error rate {{ $value | humanizePercentage }} over 5m."

for: 2m이 핵심이다. 표현식이 참이 된 순간 바로 firing이 되지 않는다. 2분 동안 계속 참이어야 비로소 firing 상태가 된다. 그 사이는 pending 상태다.

Inactive 조건 미충족 Pending for 기간 대기 중 Firing Alertmanager로 전송 조건 충족 for 경과 조건 해제 → Inactive
Alert 상태 전이

for를 짧게 설정하면 일시 스파이크에도 알림이 오고, 너무 길게 설정하면 실제 장애를 늦게 인지한다. 인프라 알림은 5분, 비즈니스 지표는 10~15분이 흔한 시작점이다.

Alertmanager: 알림의 생명주기

Prometheus는 알림 조건만 평가하고, 실제 통보 처리는 Alertmanager가 담당한다. Alertmanager가 하는 일은 네 가지다.

  1. 그루핑(Grouping): 같은 조건으로 발생한 여러 알림을 하나의 메시지로 묶는다. 인스턴스 50개가 동시에 다운됐을 때 50개의 Slack 메시지가 오지 않게 한다.
  2. 라우팅(Routing): 레이블을 기준으로 알림을 적절한 수신자(팀, 채널)로 보낸다.
  3. 억제(Inhibition): 상위 경보가 발생하면 하위 경보를 묵힌다. 노드가 다운됐을 때 그 노드의 서비스 알림을 추가로 보내지 않는 것이 전형적인 사례다.
  4. 침묵(Silence): 계획 유지보수 중에 특정 레이블 집합의 알림을 임시로 차단한다.
# alertmanager.yml
route:
  group_by: ['alertname', 'cluster']
  group_wait: 30s        # 첫 알림 후 추가 알림을 묶어 기다리는 시간
  group_interval: 5m     # 같은 그룹에 새 알림 발생 시 재전송까지 대기
  repeat_interval: 1h    # 미해결 알림 반복 전송 주기
  receiver: 'slack-default'
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty-critical'

receivers:
  - name: 'slack-default'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/...'
        channel: '#alerts'
        title: '[{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}'
  - name: 'pagerduty-critical'
    pagerduty_configs:
      - routing_key: '<integration-key>'

inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'cluster', 'service']

group_wait이 짧으면 알림이 빠르지만 연속 장애 시 그루핑이 덜 된다. group_interval은 같은 그룹에 새 알림이 생겼을 때만 영향을 준다. repeat_interval은 문제가 계속 지속될 때 담당자가 알림을 잊지 않게 주기적으로 상기시켜 주는 역할이다.

전체 흐름 정리

Prometheus TSDB Rule Evaluator Recording rules
→ 새 시계열 저장
Alerting rules
→ pending / firing
Alertmanager 그루핑 라우팅 억제 / 침묵 Slack / PagerDuty
Email / Webhook
PromQL에서 알림 전달까지의 흐름

실무 체크리스트

영역체크할 것
Counterrate()로 사용; 절댓값 직접 비교 금지
Histogrambucket 경계를 예상 값 분포에 맞게 설정
레이블 카디널리티user_id, request_id 같은 고유값 레이블 금지
Recording rule대시보드에 반복 등장하는 쿼리를 미리 계산; 이름은 level:metric:ops
Alerting for일시 노이즈를 걸러 줄 정도의 기간 설정
Alertmanager grouping폭탄 알림(alert storm) 방지
Inhibition종속 시스템 다운 시 하위 알림 억제
Silence유지보수 창마다 미리 설정

한 줄 정리

PromQL은 Instant vector와 Range vector를 레이블 기준으로 집계하는 언어다. Recording rules는 반복 쿼리의 비용을 줄이고, Alerting rules의 for 절은 일시 노이즈를 걸러내며, Alertmanager가 그루핑·라우팅·억제·침묵으로 알림의 실제 전달을 관리한다.

References

  • https://prometheus.io/docs/prometheus/latest/querying/basics/
  • https://prometheus.io/docs/prometheus/latest/querying/functions/
  • https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/
  • https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/
  • https://prometheus.io/docs/alerting/latest/alertmanager/
  • https://signoz.io/guides/promql-cheat-sheet/
  • https://last9.io/blog/prometheus-recording-rules/
  • https://victoriametrics.com/blog/alerting-recording-rules-alertmanager/
  • https://oneuptime.com/blog/post/2026-01-25-promql-queries-alerting/view