Ir al contenido

Reglas de alerta

mikroscope dashboards gen escribe, junto a cada dashboard, un fichero de aprovisionamiento de las alertas unificadas de Grafana con las reglas que se desprenden de los propios contadores de fallos de los dashboards, del registro del kernel que lee el agente y de las detecciones del colector. Todo umbral es cero (un contador que no debería moverse), una muestra (la regla del agente en silencio), una proporción de un techo que publicó el propio equipo o, en una regla, un múltiplo del último día del propio equipo. Ninguno es un número compilado para un router concreto.

Fichero Reglas Lenguaje de consulta
dashboards/mikroscope-alerts-influxdb.yaml 14 SQL de InfluxDB 3
dashboards/mikroscope-alerts-prometheus.yaml 15 PromQL
dashboards/mikroscope-alerts-postgres.yaml 10 SQL de PostgreSQL

El fichero de InfluxDB tiene una regla menos porque “The sampler is slipping ticks” todavía no tiene forma en SQL. El contador sí llega a InfluxDB —el colector lo lee del /sampler del agente y escribe mikroscope_sampler.slipped—, así que la regla se podría escribir; no se ha escrito.

El fichero de PostgreSQL se traduce del de InfluxDB, y además deja fuera las reglas que el esquema SQL no puede responder con la misma forma. mikroscope-l2-loop y mikroscope-port-link-down suman un recuento por muestra de registros de puerto del kernel, y el destino SQL escribe en su lugar una fila por registro del kernel, en mikroscope_event. mikroscope-port-errors nombra una columna por contador del MAC, y el destino SQL escribe mikroscope_api_ifcounter con una fila por contador. mikroscope-bridge-port-dark queda fuera por la misma razón: nombra rx_packet, tx_unicast y tx_broadcast como columnas, y lee bridge, que esa tabla tampoco tiene. La traducción las descarta en vez de escribir una consulta que parece correcta y responde a otra cosa. Una prueba unitaria comprueba cada columna que lee cada consulta de alerta de PostgreSQL contra las tablas que declara el destino SQL; lee el esquema, no una base de datos (no ejecutadas contra PostgreSQL).

Cada fichero es apiVersion: 1 con un grupo de reglas, mikroscope, en una carpeta llamada mikroscope, organización 1, evaluado cada minuto. Las reglas se aprovisionan en vez de ir dentro de los dashboards, así que un operador que no quiera ninguna no copia nada. forward --grafana, dashboards publish y dashboards import no instalan ninguna, y uninstall --targets dashboard no quita ninguna.

  1. Sustituye el marcador de la fuente de datos por el UID de tu fuente de datos (mikroscope-<almacén> si la creó el colector o dashboards publish) y escribe el fichero en el directorio de aprovisionamiento de Grafana. Los ficheros de aprovisionamiento no resuelven la entrada ${DS_MIKROSCOPE} de un dashboard, así que la fuente de datos es un marcador literal, DS_UID_PLACEHOLDER:

    Ventana de terminal
    sed 's/DS_UID_PLACEHOLDER/<uid>/g' dashboards/mikroscope-alerts-influxdb.yaml \
    > /etc/grafana/provisioning/alerting/mikroscope-alerts-influxdb.yaml

    Usa el fichero que corresponda a la fuente de datos a la que pertenece el UID. /etc/grafana/provisioning/alerting/ es la ruta que nombra la cabecera del propio fichero generado; el directorio es cosa de Grafana.

  2. Reinicia Grafana, o pide a su API de administración que recargue los ficheros aprovisionados. El formato del fichero y la recarga están en la guía de aprovisionamiento de alertas por fichero de Grafana.

Todas las reglas tienen la misma forma, la que escribe el propio editor de reglas de Grafana:

  1. A — la consulta, contra tu fuente de datos, con un rango de tiempo relativo de los últimos 600 s. Toda consulta SQL y toda consulta de Prometheus sobre un contador acota además su propia ventana (1, 2, 5 o 10 minutos, o 1 hora, más abajo; la regla de despertares lee además las 24 horas anteriores a sus 10 minutos, diga lo que diga el rango de 600 s de A); las dos reglas de Prometheus sobre gauges, la térmica y la de conntrack, leen el último valor, y la de la cola de salida toma el máximo de su gauge en el último minuto.
  2. B — reduce A a un número por serie con last, descartando los valores no numéricos.
  3. C — compara B con el umbral. C es la condición de la regla.

Cada regla lleva las etiquetas severity (critical o warning) y source: mikroscope, una anotación summary y execErrState: Error. Lo que hace Grafana después con una regla cuya consulta falla es comportamiento de Grafana, descrito en su propia documentación de los estados Error y No Data (no probado aquí).

Las reglas de alerta
Regla (uid)Salta cuandoUmbral (C)SeveridadforSin datos significaAlmacenes
mikroscope-agent-silentllegó al almacén menos de 1 muestra nueva en los últimos 2 minutos< 1critical2mAlertinglos tres
mikroscope-softnet-dropssoftnet_stat descartó un paquete en los últimos 5 minutos> 0critical0sOKlos tres
mikroscope-oom-killoom_kill de /proc/vmstat se movió en los últimos 5 minutos> 0critical0sOKlos tres
mikroscope-detectionscualquier detección en los últimos 5 minutos salvo microburst e ipc-collapse, que se dibujan y se guardan pero no avisan> 0warning0sOKlos tres
mikroscope-thermal-near-criticaluna zona al 85 % o más de su propio disparo crítico> 0critical1mOKlos tres
mikroscope-conntrack-near-limitobjetos activos de nf_conntrack por encima de 0,8 del límite del kernel> 0,8warning5mOKlos tres
mikroscope-agent-oomel propio cgroup del agente registró un OOM kill en los últimos 5 minutos> 0critical0sOKlos tres
mikroscope-l2-loopun registro de own-address en cualquier puerto en los últimos 5 minutos> 0critical0sOKInfluxDB 3, Prometheus
mikroscope-port-link-downun registro de link-down en cualquier puerto en los últimos 5 minutos> 0warning0sOKInfluxDB 3, Prometheus
mikroscope-port-errorsel MAC de algún puerto contó un error tipificado —desbordamiento, FCS, colisión— durante 5 minutos seguidos> 0warning5mOKInfluxDB 3, Prometheus
mikroscope-bridge-port-darkun puerto de bridge recibió paquetes mientras el bridge no le envió ni una trama unicast ni una broadcast, durante 10 minutos> 0warning10mOKInfluxDB 3, Prometheus
mikroscope-wakeup-stormla tasa de cambios de contexto de los últimos 10 minutos supera 4 veces su media de las 24 horas anteriores, durante 10 minutos> 4warning10mOKlos tres
mikroscope-egress-queue-dropsla cola de salida de algún puerto descartó un paquete en cada uno de los últimos 10 minutos: congestión sostenida, nunca una ráfaga suelta> 0warning10mOKlos tres
mikroscope-ecc-failurela NAND informó de un fallo ECC no corregible en la última hora> 0critical0sOKlos tres
mikroscope-ticks-slippedel muestreador perdió un tick por retraso en los últimos 5 minutos> 0warning5mOKPrometheus

“Sin datos significa” es el noDataState de la regla. La regla del agente en silencio es la única en la que el silencio es el fallo, así que la ausencia de datos la hace saltar; para todas las demás, no tener datos es la lectura sana.

El título de cada regla, en inglés como aparece en Grafana, y debajo una traducción abreviada de su anotación summary (el texto generado está en inglés):

  • mikroscope agent stopped delivering samples. No llegaron muestras nuevas al almacén en los últimos dos minutos: se paró el agente, se paró el colector o se cortó el camino entre ellos. Todas las demás reglas están ciegas mientras esta salta.
  • Packets dropped in the kernel receive path. softnet_stat descartó un paquete: una cola por CPU estaba llena. Pérdida inequívoca dentro del router, invisible para cualquier contador SNMP o de RouterOS. Cero es la lectura esperada.
  • The kernel OOM-killed a process. oom_kill de /proc/vmstat se movió: el kernel mató un proceso para recuperar memoria. Qué proceso no se puede saber desde el contenedor (no hay espacio de nombres de PID).
  • The collector’s derive stage flagged an event. Saltó una regla de detección (counter-reset, agent-restart, agent-oom, reboot, link-flap, conntrack-cliff, conntrack-high, thermal-high, thermal-rising). La regla, la clave, el valor y el umbral están en la sección de detecciones y en el dashboard como anotación. microburst e ipc-collapse se dibujan y se guardan como cualquier detección, pero no la disparan: describen cómo lleva el tráfico un router sano, y fueron la mayoría de las detecciones en un día medido (medido).
  • A thermal zone is within 15 % of its own critical trip. La lectura está al 85 % o más del punto de disparo crítico declarado por la zona. El techo es el de la propia placa, leído de /sys, no un número compilado.
  • The connection table is above 80 % of nf_conntrack_max. Objetos activos de nf_conntrack por encima del propio techo del kernel. Pasado el techo, el router descarta las conexiones nuevas. El límite es el sysctl que leyó el agente, no un número compilado.
  • The sampler is slipping ticks. Hubo ticks que terminaron después de que tocara el siguiente. La cadencia no se está cumpliendo: el equipo va falto de CPU, el conjunto de fuentes es demasiado caro para la cadencia, o la cuota de CPU del contenedor limitó al agente (consulta el contador de limitación del observador).
  • mikroscope’s own container was OOM-killed. El kernel mató un proceso dentro del cgroup del agente: el anillo de captura y las capturas se han perdido, y todos los números de la ventana son sospechosos. Sube --memory-max o baja RATE_HZ, BUFFER_S o CAPTURE_MB.
  • The bridge received its own address back: a layer-2 loop signature. El registro del kernel informó de received packet on <port> with own address as source address: una trama que envió el router volvió a entrar, que es el aspecto que tiene un bucle a través de un switch o un punto de acceso aguas abajo. La etiqueta del puerto dice de qué cable se trata. Se lee de /dev/kmsg con el agente, sin API. La forma de InfluxDB necesita un almacén que haya tenido al menos un registro de puerto clasificado por kind. El caso real del bucle de capa 2 muestra la firma.
  • A port’s link went down. El registro del kernel informó de un link-down en un puerto: un cable desconectado, un par que se reinició o se apagó, una renegociación. La detección de link-flap del colector cubre el caso repetido; esto es el suceso único. Se lee de /dev/kmsg con el agente, sin API; el puerto, su comentario y su rol están en los sucesos de puerto de la sección del registro del kernel.
  • A port is counting typed MAC errors. El MAC de un puerto está contando errores tipificados: tramas que no pudo aceptar. El más común en una LAN conmutada es rx-overflow, la FIFO de recepción llenándose más rápido de lo que el chip la drena, y es una firma de microrráfaga y no de carga. Los errores de FCS y las colisiones significan otra cosa: cableado, dúplex, un puerto muriéndose. Necesita la capa de API: un contador del MAC no se ve desde dentro del contenedor. No distingue un error real de un reinicio del contador, así que un router que se reinicia dentro de la ventana la dispara una vez.
  • A bridge port is receiving but the bridge sends it nothing. Un puerto miembro de un bridge ha recibido paquetes durante diez minutos mientras el bridge no le entregó ni una trama unicast ni una broadcast. Lo que hay detrás transmite y no recibe nada de vuelta: STP mantiene el puerto descartando, o el bridge aprendió todos los hosts de detrás por otro camino. RouterOS muestra el puerto en marcha y sin errores todo el tiempo. Un bucle de capa 2 se lee así en el puerto al que el bridge ha dejado de entregar (caso real). Se espera que salte en un diseño redundante, donde un puerto alternate de RSTP descarta a propósito, y en un puerto con broadcast-flood=no u horizon. Necesita la capa de API.
  • The kernel is switching context four times as often as over its last day. Algo empezó a despertarse muy a menudo: un proceso o un driver en espera activa, un cliente de monitorización, un contenedor en un bucle cerrado. Mira qué empezó cuando saltó (/user/active, contenedores nuevos, una integración nueva) y la sección de interrupciones y softirqs. Una integración de monitorización que consulta el router por la API es una de las causas (caso real). Un cambio deliberado, como un contenedor nuevo o un conjunto de reglas más pesado, también la dispara.
  • A port’s egress queue has been dropping every minute for ten minutes. La cola de salida de un puerto ha descartado paquetes en cada uno de los últimos diez minutos. A diferencia de las demás reglas de contador, el contador de esta sí debe moverse: descartar es como una cola llena le dice a quien envía que afloje. Lo que la dispara es un enlace sencillamente demasiado pequeño para lo que se le pide llevar, o un shaper puesto por debajo del tráfico. Necesita la capa de API.
  • The NAND reported an uncorrectable ECC failure. ecc_failures subió en una partición MTD: una lectura que la corrección de errores no pudo arreglar, es decir, pérdida de datos en la flash. Cualquier incremento es un incidente.
# mikroscope-agent-silent (< 1)
sum(increase(mikroscope_samples_total[2m]))
# mikroscope-softnet-drops (> 0)
sum(increase(mikroscope_softnet_total{kind="dropped"}[5m]))
# mikroscope-oom-kill (> 0)
sum(increase(mikroscope_vm_events_total{event="oom_kill"}[5m]))
# mikroscope-detections (> 0)
sum(increase(mikroscope_collector_detections_total{rule!~"microburst|ipc-collapse"}[5m]))
# mikroscope-thermal-near-critical (> 0)
count(mikroscope_thermal_celsius >= on(zone) 0.85 * mikroscope_thermal_critical_celsius)
# mikroscope-conntrack-near-limit (> 0.8)
max(mikroscope_slab_active_objects{cache="nf_conntrack"} / mikroscope_slab_limit_objects{cache="nf_conntrack"})
# mikroscope-ticks-slipped (> 0)
sum(increase(mikroscope_slipped_total[5m]))
# mikroscope-agent-oom (> 0)
sum(increase(mikroscope_self_oom_kills_total[5m]))
# mikroscope-l2-loop (> 0)
sum(increase(mikroscope_kmsg_port_records_total{kind="own-address"}[5m]))
# mikroscope-port-link-down (> 0)
sum(increase(mikroscope_kmsg_port_records_total{kind="link-down"}[5m]))
# mikroscope-port-errors (> 0)
sum(increase(mikroscope_api_interface_counter_total{counter=~"rx-overflow|rx-fcs-error|rx-fragment|rx-too-short|rx-too-long|rx-jabber|tx-fcs-error|tx-late-collision|tx-excessive-collision"}[5m]))
# mikroscope-bridge-port-dark (> 0)
count((sum by (interface) (increase(mikroscope_api_interface_counter_total{counter="rx-packet"}[10m])) > 0) and on (interface) (sum by (interface) (increase(mikroscope_api_interface_counter_total{counter="tx-unicast"}[10m])) == 0) and on (interface) (sum by (interface) (increase(mikroscope_api_interface_counter_total{counter="tx-broadcast"}[10m])) == 0) and on (interface) (mikroscope_api_interface_info{bridge!=""}))
# mikroscope-wakeup-storm (> 4)
sum(rate(mikroscope_context_switches_total[10m])) / sum(rate(mikroscope_context_switches_total[24h] offset 10m))
# mikroscope-egress-queue-drops (> 0)
max(max_over_time(mikroscope_api_interface{kind="tx_queue_drops"}[1m]))
# mikroscope-ecc-failure (> 0)
sum(increase(mikroscope_mtd_ecc_failures_total[1h]))

Las 15 leen el /metrics del colector, que es la única exposición que hay — Configurar en Grafana tiene el único trabajo de scrape. mikroscope_slipped_total está entre ellas: el agente es el dueño del ticker y lo único que puede contar un tick perdido, e informa del número por /sampler, que el colector lee cada minuto y renderiza. Así que la regla se dispara sobre una cifra de como mucho un minuto en vez de un scrape, que para un contador que vale 0 en un equipo sano es la misma alerta.

  • Cero, para un contador que no debería moverse. Descartes de RX del kernel, OOM kills del kernel, detecciones, ticks perdidos por retraso, OOM kills del propio agente, fallos ECC no corregibles, errores MAC tipificados en cualquier puerto y los registros de puerto del kernel cuyo kind es own-address o link-down. Un equipo sano lee cero en cada uno.
  • Cero puertos de bridge a oscuras, durante diez minutos. mikroscope-bridge-port-dark cuenta los puertos de bridge que recibieron paquetes mientras el bridge no les envió ni unicast ni broadcast; en un bridge sano el recuento es 0, y el periodo de espera de 10 minutos es lo que impide que un momento de calma la dispare.
  • Una muestra, para el agente en silencio. Menos de una muestra en dos minutos es ninguna, a cualquier cadencia configurada.
  • Una proporción del propio disparo térmico de la placa. El 85 % del punto de disparo crítico más bajo que declara cada zona, que el agente lee de /sys/class/thermal y envía junto a cada lectura. Una zona que no declara disparo crítico queda fuera de la consulta en vez de compararse con un techo inventado.
  • Una proporción del propio límite de conexiones del kernel. 0.8 del límite de nf_conntrack que leyó el agente. La ocupación sale de /proc/slabinfo, que necesita un contenedor privilegiado.
  • Cero otra vez, para un contador que sí debe moverse — con el juicio en la duración. La cola de salida es el único caso aquí en que la lectura sana no es exactamente cero en todos los equipos: descartar es como una cola llena le dice a quien envía que afloje, así que un enlace brevemente saturado descarta unos cuantos paquetes y está funcionando como se diseñó. Un umbral en paquetes por segundo sería un número que el equipo no publica, así que mikroscope-egress-queue-drops mantiene el cero y pregunta solo por el último minuto con un periodo de espera de diez: hacen falta diez minutos seguidos descartando para que dispare, y ninguna ráfaga puede lograrlo por grande que sea (una ráfaga medida). Esta es la forma que hay que copiar para cualquier regla futura cuya lectura sana no sea cero.
  • Un múltiplo del último día del propio equipo. Una tasa de cambios de contexto no tiene un valor sano que sirva para todas las placas, así que mikroscope-wakeup-storm compara el router consigo mismo: la tasa media de los últimos diez minutos frente a la media de las 24 horas anteriores, y salta por encima de 4 (cocientes sanos y de tormenta). Cada lado se divide entre los minutos que cubre de verdad, y la regla espera a tener 12 horas de base, de modo que un almacén con menos de un día no parece una tormenta. La regla anuncia un cambio de régimen y se apaga cuando la nueva tasa pasa a ser la base.

Las reglas no alertan por squeezes de softnet: en el router medido, alrededor del 11,2 % de las muestras por CPU llevan un squeeze, así que alertar con “squeeze > 0” te despertaría para siempre. Lo que llega en su lugar a la alerta de detecciones es la detección microburst: tres muestras de ráfaga en una CPU en 60 s. Una muestra de ráfaga es aquella en la que una cola de softnet descartó un paquete, o agotó su presupuesto más veces que el percentil 90 móvil de esa CPU y al menos tres, mientras el recuento de paquetes de la muestra estaba en su mediana móvil o por debajo. Consulta Reglas de detección.

  • Qué proceso. La regla de OOM dice que el kernel mató algo. Desde dentro del contenedor no hay espacio de nombres de PID que diga qué.
  • Qué puerto. Toda regla de puerto se reduce a un número: las dos del registro del kernel y la de errores MAC suman sobre los puertos, la de la cola de salida toma el máximo y la de puerto de bridge a oscuras cuenta puertos. Así que una regla que salta dice que hubo una firma de bucle, un link-down o un puerto a oscuras, no en qué cable. El puerto está en los dos paneles de sucesos de puerto de la sección del registro del kernel, con su comentario y sus listas de interfaces, o en la sección de tráfico por interfaz.
  • Los puntos ciegos de un agente sin privilegios. Las reglas de la tabla de conexiones y de ECC leen fuentes que necesitan un contenedor privilegiado. Sin él esas medidas nunca llegan al almacén, y en Prometheus una consulta sobre una métrica inexistente no devuelve datos — lo que estas reglas leen como OK.
  • Un colector sin la capa de API. Las reglas de errores de puerto, de puerto de bridge a oscuras y de cola de salida leen contadores de RouterOS que solo consulta la capa de API. Con --api-mode off nada de eso llega al almacén: en Prometheus las tres reglas no leen datos y en PostgreSQL la de la cola de salida, la única de las tres en ese fichero, lee 0; las dos cosas son OK. En un almacén InfluxDB que nunca ha tenido esas tablas las consultas fallan y se aplica execErrState: Error.
  • Una tabla que el almacén nunca ha tenido. InfluxDB 3 rechaza al planificarla una consulta que nombra una tabla o una columna inexistente, así que en un almacén que nunca ha tenido una detección, o mikroscope_mtd con un agente sin privilegios, la consulta de esa regla debería fallar y aplicarse execErrState: Error en lugar de OK (no observado).
  • Nada mientras salta la regla del agente en silencio. Todas las reglas leen el mismo flujo — incluida la de ticks perdidos por retraso, cuya única consulta va contra el colector, no contra el agente—, así que sin muestras llegando leen cero o ningún dato, y las dos cosas son OK.

Qué formas de estas reglas se han cargado en Grafana y se han visto evaluar, y lo que no se ha probado, está en Probado en.