Перейти к контенту

Аудит алертинга Grafana: 16 из 209 правил не могли сработать

Проверили не «горит ли алерт», а «может ли он загореться вообще». Для каждого из 209 правил посчитали серии запроса через источник данных самого правила и проверили базовую метрику без порогов. Сломанных слепых правил оказалось 16; все закрыты, а с 22.09 ежедневный сторож отличает «ноль по замыслу» от правила-сироты.

16 из 209
правил не могли сработать никогда (аудит 22.08.2026)
16 → 0
сломанных правил: 15 исправлены в день аудита, последнее снято 22.09
0 → 1
доказательство срабатывания: 3 переписанных и 1 новое правило прогнаны с живым и со сдвинутым за порог значением
0
необъяснённых слепых правил среди правил на PromQL на 14.10.2026; правила по логам сторож пока отдаёт как ошибки запроса, 3 правила на паузе учтены отдельно
71,5 %
столько времени были здоровы два узла: снять фильтр, как советовал сам аудит, значило получить вечно горящий алерт

Резюме

Слепым мы называем правило алертинга, чей запрос возвращает ноль серий. В Grafana оно выглядит здоровым (health=ok, state=Normal) и ничем не отличается от рабочего, но сработать не может никогда.

22 августа 2026 года мы проверили все правила алертинга в инфраструктуре из нескольких гипервизоров и десятков виртуальных машин. Из 209 правил с выражением ноль серий давали 43. Из них 27 молчали по замыслу, а 16 были сломаны: источник метрики умер, переехал или сменил имя. 15 исправлены в тот же день, последнее снято 22.09. Четыре правила, три переписанных и одно новое, доказанно срабатывают.

С 22.09 вторая половина метода работает в ежедневном стороже: он отличает «ноль по замыслу» от правила-сироты, а при сомнении зовёт человека. На 14.10 необъяснённых слепых правил среди правил на PromQL нет; правила по логам сторож пока отдаёт как ошибки запроса.


1. Гипотеза и метод

Исходная гипотеза: при переезде узлов на декларативную ОС (NixOS) часть источников метрик не переехала, и алерты на них молчат.

Метод состоит из двух шагов:

  1. Для каждого из 209 правил с выражением (PromQL или LogQL) посчитано число серий его запроса через прокси того источника данных, к которому привязано правило. Так правила по логам считаются честно. Скрипт по расписанию, который считал слепые правила и до аудита, отдаёт их как ошибки запроса.
  2. Для каждого нуля проверена базовая метрика без порогов и фильтров. Только это отличает «ноль по замыслу» (стражи absent(), пороги при живой базе, окна по времени) от «источник умер».

Проверка наличия серий сама по себе не новость. Например, pint от Cloudflare (проверка promql/series) спрашивает живой Prometheus, есть ли у правила серии, и разбирает, почему их нет. Здесь правила живут в Grafana, и ту же проверку мы собрали через прокси источников данных; умеет ли pint разбирать правила Grafana, мы не проверяли. К проверке серий добавлен второй вопрос: сработает ли правило, когда значение действительно уйдёт за порог (раздел 3).

Правилос выражениемСерии запросачерез свой источникБазовая метрикабез пороговНольпо замыслуСирота:источник мёртвПочинкаи прогон 0 / 1 0 серий метрика живаметрики нет
100%
Ctrl+Колесо или перетаскивание

Рис. 1. Как аудит отделяет «ноль по замыслу» от сломанного правила.

2. Что нашли: 16 правил и три причины

причинаправилчто произошло
пересборка узлов на декларативную ОС9туннели, по которым сервер мониторинга забирает метрики с узлов, потеряли ключи; часть сборщиков метрик сознательно не вошла в первую версию миграции
источник метрики переехал или сменил имя3метрика переехала на другой узел или получила новое имя, а правило смотрело на старое место
миграция агента сбора логов4новый конфиг агента потерял метку контейнера: правила по логам сравнивали с пустотой, хотя сам сервис был жив

Гипотеза подтвердилась только наполовину: с переездом на NixOS связаны 9 правил из 16, остальные сломались по другим причинам.

Урок первой строки таблицы: у туннеля мониторинга две половины конфигурации, одна на сервере мониторинга, другая на узле. Пересборка, которая обновляет одну половину и теряет другую, отключает сбор метрик, а правила над этими метриками становятся слепыми.

Что сделали:

  • половину на узлах объявили в декларативной конфигурации, чтобы следующая пересборка её не потеряла;
  • половину на сервере мониторинга обновили, сверив новые данные узлов по независимому каналу, а не приняв их на веру при первом подключении;
  • агент сбора логов перевели на обнаружение контейнеров и проверили метки в Loki;
  • правила, смотревшие на старые имена и старое место, переписали.

3. Доказательство срабатывания

Ноль на живых данных ничего не доказывает: правило, которое не может сработать, тоже показывает ноль. Поэтому каждое из четырёх правил, трёх переписанных и одного нового, прогнано через API вычисления правил Grafana дважды. Живое значение даёт 0, значение, сдвинутое за порог, даёт 1. Только эта пара доказывает, что правило срабатывает, когда значение за порогом.

Новое правило срабатывает, если сборщик завис. От этого сборщика берут данные два соседних правила, и его заморозка ослепляла их молча.

4. Ежедневный сторож: классификатор вместо ручного порога

Скрипт по расписанию раз в сутки считает слепые правила; он работал и до аудита. До 22.09 у алерта «слепых правил стало больше» был ручной порог: замеренное и вписанное в правило число. Оно устаревало с каждым новым стражем absent(): у такого правила ноль серий означает здоровье, поэтому счёт слепых растёт от нормальной работы. Алерт горел месяцами и перестал восприниматься как сигнал.

22.09 в скрипт добавили классификатор. Он делит слепоту на два вида, причём не по форме запроса, а по вопросу «существует ли метрика»:

  • метрика есть, а запрос пуст: фильтр, absent() или селектор ничего не выбрали, и это здоровье;
  • метрики нет вовсе: правило сторожит то, чего не существует, и это сирота.

Три решения вокруг классификатора:

  • При сомнении правило считается необъяснённым. Непонятный запрос уходит к человеку. Классификатор, который при незнании молча ручается за правило, хуже отсутствующего.
  • Контроль в обе стороны. Отдельный набор из 8 случаев, включая положительные. Классификатор, который всегда отвечает «по замыслу», дал бы ноль необъяснённых и выглядел бы идеальным.
  • Порог без ручного числа. Алерт горит, если есть хотя бы одно необъяснённое правило. Пересчитывать базовую линию больше нечего.

Что не получилось с первого раза: в первой версии классификатора нашлись три ошибки. Он смотрел на операторы в запросе и ошибался там, где сравнение живёт в выражении Grafana, а не в PromQL. Классификация шла по обрезанной для печати строке запроса, и сравнение в её хвосте было невидимо. Имена меток из by (...) принимались за имена метрик. Все три ошибки исправлены.

После суток разбора алертов 22.09, включая замену порога, горящих правил стало 4 вместо 11; из четырёх одно горит по замыслу. 14.10 сторож научился учитывать правила, поставленные на паузу: они идут отдельной строкой. На эту дату среди правил на PromQL необъяснённых слепых нет, на паузе 3. Одно из трёх поставлено на паузу в тот же день: его метрику пишет только генератор тестовых сценариев, который сейчас не запускают. Правила по логам сторож пока отдаёт как ошибки запроса.

5. Рекомендацию аудита опроверг замер

Аудит предлагал снять у одного правила фильтр, исключавший два узла: теперь они пишут нужную метрику, и фильтр будто бы зря слепит правило. Перед правкой мы проверили это замером за 7 суток. Метрику узлы действительно пишут, но здоровы лишь 71,5 % времени: 102 и 120 переходов в «нездоров». Без фильтра получился бы алерт, который горит постоянно. Фильтр оставлен, замер записан рядом с ним.

Вывод: рекомендация аудита остаётся гипотезой. Её проверяют замером, прежде чем выполнять.

6. Чего этот метод не видит

  • Частичная слепота. Серии есть, но правило видит не все узлы, которые должно. Аудит нулей её не замечает.
  • Правило, невыполнимое по построению. Пример из практики: пока искомого состояния нет, метрика есть и равна нулю; когда оно наступает, метрика пропадает, а «нет данных» объявлено нормой. Ни одно состояние мира такое правило не зажигает. Аудит нулей в здоровом состоянии его пропускает: серии есть. Проверка двумя значениями тоже: сдвиг значения за порог не воспроизводит пропажу метрики. Ловит только вопрос: существует ли значение метрики, при котором правило сработает, и доходит ли метрика именно в этом состоянии.
  • Чем это отличается от привычных проверок. Усталость от алертов (alert fatigue) видна сразу: алертов слишком много. Слепое правило даёт обратную и невидимую беду: алерта нет, когда он нужен, и метрики шума её не покажут. Тесты правил (promtool test rules) гоняют выражение на синтетических рядах, а health=ok значит только, что запрос выполнился; ни то, ни другое не говорит, есть ли у правила живые серии. Постоянно горящий алерт-пульс (dead man's switch) ловит отказ всего конвейера оповещений, а не отдельное правило, у которого пропал источник. Состояние No Data в Grafana помогает, только если правило настроено считать отсутствие данных тревогой; у правил, для которых ноль серий нормален, такая настройка даёт ложные тревоги.
  • Метрика, зависшая в Pushgateway. Группа метрик, которую давно никто не обновляет, продолжает отдавать серии. Для аудита её источник выглядит живым, хотя данных от него давно нет.

Выводы

  • Состояние health=ok не означает, что правило может сработать. Проверять надо число серий через источник данных самого правила и базовую метрику без порогов.
  • Срабатывание доказывает пара прогонов: живое значение даёт 0, сдвинутое за порог даёт 1.
  • Классификатор при сомнении отдаёт правило человеку и проверяется контролем в обе стороны: ноль на живых данных ничего не доказывает.
  • Рекомендации аудита, как и любые гипотезы, проверяются замером до правки.
Аудит алертинга Grafana: 16 из 209 правил не могли сработать | Софтэнк