Prometheus recording rules: предварительная агрегация дорогих запросов

Published: 2026-03-11

Range-запросы Prometheus по меткам с высокой кардинальностью работают медленно. Запрос за 7 дней по сотням подов, выполняемый при каждой загрузке панели Grafana, обходится дорого — и эта нагрузка накапливается. Recording rules решают проблему: результат вычисляется заранее, с заданным интервалом.


Как работают recording rules

Recording rule — это PromQL-выражение, которое выполняется с заданным интервалом и записывает результат как новую метрику с более простым именем. Grafana запрашивает предвычисленную метрику вместо дорогостоящего исходного выражения.

yamlapiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: recording-rules
  namespace: observability
  labels:
    release: kube-prom-stack   # должен совпадать с selector Prometheus
spec:
  groups:
    - name: recording
      interval: 30s
      rules:
        - record: job:http_requests_total:rate5m
          expr: |
            sum by (job, namespace) (
              rate(http_requests_total[5m])
            )

interval: 30s — результат обновляется каждые 30 секунд. Панели Grafana отвечают мгновенно без тяжёлого range-запроса при загрузке.


Соглашение об именовании

Стандарт: level:metric:operations

  • level — уровень агрегации (job, namespace, cluster, instance)
  • metric — имя исходной метрики
  • operations — что было сделано (rate5m, sum, p99, ratio)

Примеры:

namespace:container_cpu_usage_seconds:rate5m
job:http_request_duration_seconds:p99
cluster:node_memory_working_set_bytes:sum
job:http_errors:rate5m_ratio

Практические правила для мультикластерной установки

yamlgroups:
  - name: cluster-resources
    interval: 60s
    rules:
      - record: namespace:container_cpu_usage_seconds_total:rate5m
        expr: |
          sum by (namespace, cluster) (
            rate(container_cpu_usage_seconds_total{container!=""}[5m])
          )

      - record: pod:container_memory_working_set_bytes:sum
        expr: |
          sum by (pod, namespace, cluster) (
            container_memory_working_set_bytes{container!=""}
          )

      - record: job:http_errors:rate5m
        expr: |
          sum by (job, namespace) (
            rate(http_requests_total{status=~"5.."}[5m])
          )
          /
          sum by (job, namespace) (
            rate(http_requests_total[5m])
          )

      - record: job:http_request_duration_seconds:p99
        expr: |
          histogram_quantile(0.99,
            sum by (job, namespace, le) (
              rate(http_request_duration_seconds_bucket[5m])
            )
          )

Скорость сжигания бюджета ошибок SLO

yaml  - name: slo-burn
    interval: 60s
    rules:
      - record: job:slo_error_budget_burn:1h
        expr: |
          (
            sum by (job) (rate(http_requests_total{status=~"5.."}[1h]))
            /
            sum by (job) (rate(http_requests_total[1h]))
          ) / 0.001

      - record: job:slo_error_budget_burn:6h
        expr: |
          (
            sum by (job) (rate(http_requests_total{status=~"5.."}[6h]))
            /
            sum by (job) (rate(http_requests_total[6h]))
          ) / 0.001

Мультиоконный алерт:

yaml- alert: HighErrorBudgetBurn
  expr: |
    job:slo_error_budget_burn:1h > 14
    and
    job:slo_error_budget_burn:6h > 6
  for: 2m
  labels:
    severity: critical
  annotations:
    description: "{{ $labels.job }} сжигает бюджет ошибок со скоростью {{ $value | humanize }}x"

Скорость 14x за 1 час означает исчерпание месячного бюджета примерно за 2 дня.


Recording rules для ресурсов Kubernetes

yaml- name: k8s-resource-recording
  interval: 60s
  rules:
    - record: node:cpu_utilization:ratio
      expr: |
        1 - avg by (node) (
          rate(node_cpu_seconds_total{mode="idle"}[5m])
        )

    - record: node:memory_utilization:ratio
      expr: |
        1 - (
          node_memory_MemAvailable_bytes /
          node_memory_MemTotal_bytes
        )

    - record: persistentvolumeclaim:disk_usage:ratio
      expr: |
        1 - (
          kubelet_volume_stats_available_bytes /
          kubelet_volume_stats_capacity_bytes
        )

Где размещать PrometheusRule

Recording rules — в base/monitoring/rules/recording.yaml, применяются на всех кластерах через базовую Kustomization. Правила для конкретных окружений (разные SLO-пороги для dev и prod) — в patches/monitoring/rules/.

Один PrometheusRule на задачу: recording, node alerts, SLO alerts. Это минимизирует diff при изменении порогов.


Проверка загрузки правил

bashkubectl port-forward -n observability svc/kube-prom-stack-prometheus 9090:9090
# http://localhost:9090/rules

curl -s 'http://localhost:9090/api/v1/query?query=job:http_requests_total:rate5m' | jq '.data.result | length'

Если правило не появляется, проверьте, что label selector в PrometheusRule совпадает с конфигурацией kube-prom-stack.