본문으로 건너뛰기

4.3 Rule과 Cardinality

Recording rule은 자주 쓰거나 계산 비용이 큰 PromQL 결과를 새 time series로 저장합니다. Alerting rule은 query 조건이 일정 시간 지속되면 alert 상태를 만듭니다. 두 rule 모두 편리하지만 잘못 집계하면 틀린 숫자를 빠르게 반복하게 됩니다.

Recording rule

TPS를 instance 단위로 미리 계산합니다.

groups:
- name: postgres-recording
interval: 30s
rules:
- record: instance:pg_transactions_per_second:rate5m
expr: |
sum by (instance, cluster, environment) (
rate(pg_stat_database_xact_commit{datname!~"template.*"}[5m])
+ rate(pg_stat_database_xact_rollback{datname!~"template.*"}[5m])
)

이름은 level:metric:operations 형태로 읽을 수 있게 만듭니다. instance는 aggregation 수준이고 rate5m은 적용한 연산을 나타냅니다.

Alerting rule

- alert: PostgreSQLExporterCannotReachDatabase
expr: up{job="postgres"} == 1 and pg_up == 0
for: 2m
labels:
severity: ticket
annotations:
summary: "Exporter is reachable but PostgreSQL collection fails"
description: "instance={{ $labels.instance }}, cluster={{ $labels.cluster }}"
runbook_url: "https://dbalog.dev/observability/reliability-operations/incident-runbook"

for는 짧은 network blip이나 rolling restart가 바로 firing되는 것을 막습니다. 사용자 영향이 큰 증상은 더 빠르게, 예방성 경보는 더 길게 기다리도록 구분합니다.

조건 지속 시간에 따라 Normal/Pending/Firing으로 전이하는 Alert 상태

Syntax 검증

promtool check rules prometheus/postgres.rules.yml

Rule의 실제 결과는 unit test로 고정할 수 있습니다.

rule_files:
- postgres.rules.yml

evaluation_interval: 1m

tests:
- interval: 1m
input_series:
- series: 'up{job="postgres",instance="db-a",cluster="lab"}'
values: '1+0x5'
- series: 'pg_up{job="postgres",instance="db-a",cluster="lab"}'
values: '0+0x5'
alert_rule_test:
- eval_time: 3m
alertname: PostgreSQLExporterCannotReachDatabase
exp_alerts:
- exp_labels:
cluster: lab
instance: db-a
job: postgres
severity: ticket
exp_annotations:
summary: "Exporter is reachable but PostgreSQL collection fails"
description: "instance=db-a, cluster=lab"
runbook_url: "https://dbalog.dev/observability/reliability-operations/incident-runbook"
promtool test rules postgres.rules.test.yml

Cardinality budget

새 collector를 켜기 전후에 sample 수를 비교합니다.

scrape_samples_post_metric_relabeling{job="postgres"}

Prometheus 전체에서 metric별 series 수를 확인합니다.

topk(20, count by (__name__) ({__name__!=""}))

다음 변화는 review 대상으로 둡니다.

  • 한 exporter의 sample 수가 배포 후 급증
  • queryid, table, user label 값 종류가 지속 증가
  • recording rule이 원본보다 더 많은 series를 생성
  • dashboard query가 수천 series를 반환
  • rule evaluation 시간이 interval에 가까워짐

Pre-aggregation 경계

Recording rule에서 datname을 제거하면 dashboard는 가벼워지지만 database별 원인을 볼 수 없습니다. Overview용 instance aggregation과 drill-down용 database aggregation을 별도로 둡니다.

- record: instance:pg_transactions_per_second:rate5m
expr: sum by (instance) (...)

- record: instance_datname:pg_transactions_per_second:rate5m
expr: sum by (instance, datname) (...)

사용하지 않는 모든 차원을 보존하는 것은 안전해 보이지만 비용을 그대로 유지합니다. 실제 조사 경로에 필요한 resolution만 남깁니다.

참고: Prometheus Recording rules, Defining recording and alerting rules