Ошибки и правила оповещения
Дашборд помогает человеку заметить проблему, но постоянно смотреть на него невозможно. Добавим правила оповещения и согласуем описание ошибок. Для «Пульса» выберем три условия: старая ожидающая задача, повышенная доля 5xx и отсутствие heartbeat API. Последнее проверяет путь наблюдения, а первые два относятся к пользовательской работе. Их нельзя объединять в одно общее «сервис красный», потому что дальнейшие действия отличаются.
В десятом состоянии правила читаются Prometheus из alerts.yaml. Они могут перейти в pending и firing после соответствующих интервалов. Отправки уведомления в почту, чат или paging-систему в пакете нет: Alertmanager и contact point не настроены. Поэтому наличие rule file не означает, что оператор уже будет разбужен. Для выпуска нужно отдельно выполнить настройку доставки и закрепить её владельца.
Ошибка операции и ошибочный запрос
Техническое исключение из SQL делает span ERROR и даёт безопасное событие request.failed. API возвращает 503. Ожидаемый отказ аутентификации даёт 401 без утверждения, что база сломалась. Такие различия полезны при оценке надёжности: пользователю может потребоваться вход, а оператору — восстановление зависимости. Нельзя автоматически присваивать одинаковую аварийную важность всем ответам с первой цифрой больше двух.
В событие failure не переносится произвольный error message. Для PostgreSQL timeout используется ограниченный db_timeout, остальные технические случаи получают operation_failed. Подробный разбор выполняется в закрытой среде с разрешёнными данными. Telemetry backend не становится местом хранения SQL и токенов просто потому, что incident требует подробностей. Безопасный код помогает связать событие с runbook, не раскрывая содержимое.
Задание может завершить вычисление, но потерять право фиксации из-за нового lease. Тогда outcome должен быть lease_lost, а не done. В текущем worker результат UPDATE проверяется по rowCount, чтобы лог не обещал завершение, которого нет в базе. Эта проверка показывает важный принцип: событие прикладного успеха следует после успешного изменения ответственности, а не только после возврата локальной функции вычисления.
Возраст очереди
Rule PulseQueueOld реагирует на значение старейшей queued больше минуты, сохраняющееся две минуты. Порог в минуту относится к значению gauge, а for относится к длительности истинного условия. Это два разных интервала. Если возраст пересёк порог на один scrape и быстро вернулся, оповещение не обязано перейти в firing. Так снижается шум коротких колебаний при обычном распределении работы.
Полный файл alerts.yaml состояния 10:
groups:
- name: pulse
rules:
- alert: PulseQueueOld
expr: max(pulse_queue_oldest_seconds{service="pulse-worker"}) > 60
for: 2m
labels: {severity: warning}
annotations:
summary: "Самая старая задача Пульса ждёт дольше минуты"
runbook: "incident.md: очередь и lease"
- alert: PulseApiErrors
expr: |
sum(rate(pulse_requests_total{service="pulse-api",status_class="5xx"}[5m]))
/ clamp_min(sum(rate(pulse_requests_total{service="pulse-api"}[5m])),0.001) > 0.05
for: 3m
labels: {severity: warning}
annotations:
summary: "У API Пульса повышена доля серверных ошибок"
- alert: PulseMetricsMissing
expr: absent_over_time(pulse_process_up{service="pulse-api"}[2m])
for: 2m
labels: {severity: warning}
annotations:
summary: "Нет метрик API Пульса: проверить путь наблюдения"
Порог выбран для учебного сценария и не объявлен SLA настоящего отчёта. В продукте его связывают с обещанным временем выполнения, временем реакции и стоимостью пропуска. Если отчёты обычно планируются через десять минут, минутный alarm будет бессмысленным. Если результат нужен за десять секунд, условие слишком медленное. Хорошее правило отражает значимую проблему для пользователя и понятное действие оператора.
При остановленном worker gauge может перестать обновляться. Поэтому само правило очереди не гарантирует обнаружение отказа процесса. Нужен heartbeat worker или отдельный watchdog очереди из другого работающего источника. В лаборатории добавлен pulse_process_up, и соответствующую absence-проверку можно расширить на worker. Не стоит читать старый ноль как доказательство здоровья после потери источника.
Доля серверных ошибок
Rule PulseApiErrors делит скорость 5xx на скорость всех запросов за пять минут. Условие больше пяти процентов должно удерживаться три минуты. При очень низком трафике один отказ может дать большую долю, хотя статистическое основание невелико. Для промышленного SLO дополняют условие минимальным объёмом или используют burn-rate подход с подходящими окнами. Учебная формула демонстрирует отношение, а не готовый универсальный alarm.
Класс статуса показывает общую надёжность API, но не объясняет причину. По событию firing выбирают интервал, затем traces и логи дают конкретный SQL-span или код отказа. В annotations нужно кратко назвать проблему и путь к действиям, а не вставить полный query или stack. Secret-free rule description может быть передан в систему уведомления без распространения пользовательского запроса.
После восстановления rule может вернуться в норму не мгновенно: окно rate ещё содержит прежние ошибки. Это ожидаемое поведение сглаженного измерения. Оператор должен сопоставить свежие запросы, состояние базы и trend, а не повторять rollback каждый раз, пока пятиминутное окно не очистилось. Временное окно наблюдения является частью логики реакции, поэтому его читают вместе с for.
Отсутствие телеметрии
PulseMetricsMissing проверяет отсутствие pulse_process_up за две минуты и ещё выдерживает условие. Heartbeat существует независимо от пользовательского трафика, поэтому отсутствие requests в тихий период не маскируется под отказ. Это лучше, чем alarm только по исчезновению counter, который мог вообще не создать series до первого измерения. Однако отсутствие heartbeat не указывает однозначно на приложение: могли отказать exporter, Collector или scrape.
Prometheus up для target Collector отвечает на другой вопрос: удалось ли опросить endpoint 8889. Он может быть равен единице, хотя данные API туда больше не приходят. Поэтому в расследовании сопоставляют scrape health и process heartbeat. Та же логика применяется к logs и traces: доступность query API не доказывает свежий приём данных. Путь пользователя и путь наблюдения требуют раздельных индикаторов.
Доставка и ответственность
До настоящего выпуска выбирают канал и проверяют прохождение firing до получателя в разрешённой среде. Условия дедупликации, группировка, тишина при обслуживании и escalation влияют на работу команды не меньше формулы. Мы не отправляем сообщения третьим лицам и не создаём внешние контакты в рамках этой статьи. Конфигурация rules подготовлена локально, а подключение службы уведомлений остаётся явным этапом передачи.
Оповещение должно вести к существующему runbook и иметь владельца. В следующем состоянии появится incident.md с модельным расследованием очереди. Пока annotation указывает ожидаемый путь, который будет завершён следующим уроком. Для реального выпуска файл заменяют доступным команде адресом и подтверждают, что права получателя позволяют прочитать нужные панели и данные без административного доступа ко всему backend.
Ожидаемый результат десятого состояния — вычисляемые правила с разными смыслами и корректные коды ошибок в trace/log. Мы не наблюдали firing и не подтверждали доставку: стенд не запускался. Следующая глава рассмотрит sampling и модельный incident, где отсутствие отдельных spans нельзя будет автоматически считать доказательством отсутствия работы.
Предыдущий урок: Дашборд для диагностики задержки · Следующий урок: Сэмплирование и разбор инцидента
Оглавление серии · Исходники всех состояний.
Документация: Prometheus alert rules, Prometheus functions.