Prometheus: cómo escribir alertas que no se ignoren

Dashboard con gráficas de métricas y alertas

Cualquier equipo que ha usado Prometheus lo suficiente ha vivido el mismo ciclo: al principio se añaden alertas con entusiasmo, y seis meses después el canal de on-call está inundado de ruido, nadie las mira, y cuando pasa algo serio la señal se pierde entre falsos positivos. El problema rara vez es Prometheus — es el diseño de las reglas.

Síntomas vs. causas: alerta sobre lo que importa al usuario

La regla más importante de diseño de alertas, defendida por el equipo SRE de Google en el libro SRE original, es: alerta sobre síntomas, no sobre causas.

  • Síntoma: “La tasa de errores 5xx en el endpoint /api/payments supera el 1% durante 5 minutos.”
  • Causa: “El pod payments-service-3 tiene un CPU usage del 95%.”

La diferencia importa porque un usuario no experimenta CPU alto — experimenta respuestas lentas o errores. Alertar sobre causas produce dos patologías simultáneas:

  1. Alertas falsas positivas: una causa puede disparar sin que el usuario note nada (el servicio escala automáticamente y absorbe el pico).
  2. Alertas falsas negativas: otra causa no prevista puede provocar un fallo sin ninguna alerta a nivel causa encendida.

Un buen conjunto de reglas parte de síntomas observables desde el punto de vista del cliente (latencia, error rate, saturación) y mantiene las causas como dashboards de diagnóstico, no como alertas que paginan.

Anatomía de una alerta bien escrita

Una regla de Prometheus con múltiples ventanas, anotaciones completas y etiquetas de routing queda así:

- alert: ApiHighErrorRate
  expr: |
    sum by (service) (
      rate(http_requests_total{status=~"5.."}[5m])
    )
    /
    sum by (service) (
      rate(http_requests_total[5m])
    )
    > 0.01
  for: 10m
  labels:
    severity: page
    team: platform
  annotations:
    summary: "API {{ $labels.service }} error rate above 1%"
    description: |
      Service {{ $labels.service }} has had >1% 5xx error rate for the
      last 10 minutes (current: {{ $value | humanizePercentage }}).
    runbook_url: "https://runbooks.example.com/api-error-rate"
    dashboard_url: "https://grafana.example.com/d/abc/api-overview"

Elementos clave:

  • for no trivial. Entre 5 y 15 minutos suele absorber transitorios sin retrasar excesivamente la respuesta a incidentes reales.
  • Etiquetas de routing claras: severity (page vs ticket vs info) + team permiten que Alertmanager enrute a canales distintos y que cada equipo reciba solo lo suyo.
  • Anotaciones completas: summary (una línea), description (contexto con valores interpolados), runbook_url (qué hacer) y dashboard_url (dónde mirar). Una alerta sin runbook es una invitación a pánico.

SLOs y burn rate multi-ventana

El patrón que ha ganado adopción más rápidamente en 2022-2023 es el de alertas basadas en SLO con burn rate multi-ventana y multi-umbral, popularizado por Google SRE y detallado en el capítulo 5 del SRE Workbook.

La idea: define un SLO (por ejemplo, 99.9% de éxito en 30 días, permitiendo un error budget de 0.1%). En lugar de alertar sobre tasa de error absoluta, alerta cuando estás quemando el error budget más rápido de lo sostenible:

  • Burn rate > 14.4x durante 1h → alarma crítica (consumirías el budget del mes en 2 días).
  • Burn rate > 6x durante 6h → alarma seria (consumirías el budget en 5 días).
  • Burn rate > 1x durante 24h → alarma de tendencia (vas camino de gastar el budget).

Esto alinea alertas con promesas reales al cliente (el SLO) y reduce drásticamente las páginas innecesarias. Sloth y Pyrra generan estas reglas automáticamente desde una definición declarativa de SLO.

El watchdog: alerta que siempre está encendida

Un error común: alertas silenciosas. Prometheus deja de scrape-ar, Alertmanager cae, o un error de configuración hace que las reglas no se evalúen. No llega ninguna alerta — pero tampoco llega ningún ping. Dos semanas después te das cuenta de que tu observabilidad ha estado muerta.

La solución canónica: una alerta watchdog que está siempre disparando, por diseño:

- alert: Watchdog
  expr: vector(1)
  labels:
    severity: none
  annotations:
    summary: "Prometheus is alive"

Se envía a un receptor que espera recibirla cada X minutos. Si no llega durante un umbral, el receptor (típicamente Dead Man’s Snitch o un healthcheck externo tipo Healthchecks.io) dispara su propia alerta. Esto convierte silencio en señal, en vez de ambigüedad.

Misma lógica aplica a otras ausencias críticas. Escribimos sobre este principio en las lecciones aprendidas monitorizando infraestructura con eBPF: el ruido es manejable, el silencio es mortal.

Qué pulir cada trimestre

Las alertas no son “configure and forget”. Un ritual útil para equipos on-call:

  • Revisión trimestral de top-N páginas. ¿Qué alertas han disparado más? ¿Cuántas resultaron en acción real? Las que siempre se acknowledgean sin acción se deben eliminar o ajustar.
  • Post-mortems con ítem “alertas”. Cada incidente enseña: ¿la alerta adecuada llegó a tiempo? ¿Alguna alerta irrelevante se disparó en paralelo?
  • Pruebas de alertas nuevas en staging. Simula el síntoma antes de subir la regla a producción.

Ver también: cómo aplicar pensamiento de diseño a los runbooks — los mejores runbooks están diseñados desde la perspectiva del operador bajo presión, no del autor con todo el contexto.

Conclusión

Alertar sobre síntomas, basar la gravedad en SLOs con burn rate, monitorizar la salud del propio sistema de alertas con un watchdog, y revisar trimestralmente el ratio señal/ruido: estos cuatro principios reducen la fatiga de guardia y mejoran la respuesta a incidentes reales.

Síguenos en jacar.es para más sobre observabilidad, SRE y plataforma moderna.

Entradas relacionadas