PromQL посчитал все instance: почему bool меняет результат count

Нужно показать число доступных targets. Кто-то написал count(up == bool 1), получил общее количество серверов и решил, что все они работают. Проблема становится заметной, когда один target падает: значение панели не меняется. Выражение корректно синтаксически, но сочетает две разные операции не так, как ожидал автор.

Сравнение в PromQL без bool обычно фильтрует элементы. Сравнение с bool оставляет подходящие для операции серии и превращает значения в ноль или единицу в зависимости от результата сравнения. Count считает количество элементов в векторе, а не сумму их значений. Поэтому нулевая серия тоже попадает в count.

Разобрать маленький набор

Представим три target с up равными 1, 1 и 0. У выражения up == 1 остаются две серии. У up == bool 1 сохраняются три серии со значениями 1, 1 и 0. Значит, count второго результата даёт три, а sum — два. Для количества доступных целей подходят обе следующие формы с разным ходом рассуждения:

count(up{job="api"} == 1)
sum(up{job="api"} == bool 1)

У этих форм есть существенное различие: если все имеющиеся targets недоступны, фильтр up == 1 оставит пустой вектор, и count не покажет обычный ноль. Bool сохраняет нулевые элементы, поэтому sum второй формы вернёт 0. Если нужен именно числовой индикатор доступности при all-down, выбирайте сумму. Если исчезли сами targets, обе формы требуют отдельного контроля отсутствия данных.

У up значения уже представлены нулём и единицей, поэтому часто достаточно sum(up{job="api"}). Но в более общем сравнении bool полезен: например, превратить числовой порог в индикатор выполнения условия. Главное — дальше применять операцию, которая соответствует этому индикатору.

Если нужен процент доступных targets, числитель и знаменатель должны относиться к одному набору. Деление суммы up на count(up) даёт долю доступных среди обнаруженных targets. Оно не обнаружит сервер, который полностью исчез из service discovery: такого элемента в текущем знаменателе уже нет. Для контроля ожидаемого количества нужен отдельный источник ожиданий или правило обнаружения.

Смотреть промежуточный вектор

Перед агрегацией откройте результат в табличном виде. Проверьте labels и значения для одного доступного и одного недоступного instance. Затем добавьте count или sum и убедитесь, что исчезновение меток при агрегации соответствует нужному уровню обзора. Для нескольких сервисов, например, понадобится by(job) или другой выбранный разрез.

Не заменяйте этим правилом все сравнения в алертах. Алерт с выражением, возвращающим серию со значением ноль, всё ещё может считаться активным: для алертинга важен факт присутствия элемента результата. Если используете bool внутри алерт-выражения, убедитесь, что последующее условие действительно отфильтровывает ложный случай.

Проверка на трёх значениях 1, 1, 0 занимает мало времени и сразу показывает разницу между числом серий и суммой индикаторов. Её полезно повторять при review запросов, где рядом встречаются bool, count и доли. Так синтаксически правильный запрос не превращается в панель, которая остаётся зелёной после отказа.

Продолжить практику

Одно выражение или правило становится полезным, когда связано с конкретным действием инженера. В программе курса «Prometheus и Grafana: мониторинг и observability» — метрики учебного сервиса, exporters, обзорный и диагностический дашборды, SLI/SLO и алерты с инструкциями. Практика включает воспроизведение отказа или роста задержек и расследование по сигналам системы. Это продолжение для тех, кто хочет собрать мониторинг, по которому можно принимать решения во время сбоя.

Посмотреть программу курса

Источник: официальная документация.

Другие задачи по теме: Метрики и уведомления без неверных выводов.

Продолжить на практике

  • Prometheus и Grafana: мониторинг и observability ↗

    Замечайте сбои до жалоб пользователей. Соберите мониторинг приложения: метрики Prometheus, запросы PromQL, дашборды Grafana и алерты, по которым понятно, что делать. Итог — наблюдаемый сервис и разбор учебного инцидента.