/mayday

Primary LanguageJavaApache License 2.0Apache-2.0

mayday

Сервис алертинга, отвечающий за управление конфигурациями алертов

Роль сервиса в системе алертинга

Приблизительная схема системы алертинга выглядит следующим образом:

схема системы алертинга

Часть системы алертинга, в которой участвует mayday:

схема системы алертинга_мэйдэй

В рамках данного документа будут объяснены все взаимодействия со схемы выше.

Внутреннее устройство сервиса

Структура проекта

Проект использует feature-layered структуру пакетов. Взаимодействие с prometheus, взаимодействие с alertmanager, формирование конфигураций алертов и протокол для взаимодействия с сервисом разнесены по разным корневым каталогам. Это позволяет вносить правки в конкретную "фичу" и не бояться, что они сломают соседний функционал. В сервисе есть функционал, которые переиспользуются для всех "фич" - он вынесен в пакет common.

Если вас интересует не определенный функционал сервиса, а общее понимание его устройства, то лучше начать изучение кодовой базы с класса AlertingService - он реализует thrift-протокол, через который и осуществляется взаимодействие с сервисом.

Prometheus

Prometheus содержит информацию о всех метриках, которые отдают ему экспортеры. С помощью правил алертинга (они же alerting rules) можно настроить prometheus таким образом, чтобы он на постоянной основе выполнял переданный в правиле алертинга запрос к метрикам. Если результат запроса "положителен" (true/ не 0) дольше, чем период времени, который так же передается в правиле алертинга, prometheus отправляет запрос в alertmanager.

Сервис mayday отвечает за создание и удаление правил алертинга.

API, через которое происходит взаимодействие с prometheus, описано в разделе prometheus-operator.

Alertmanager

Alertmanager содержит информацию о том, кому, куда и с какой периодичностью отправлять алерты. Чтобы лучше понимать специфику алертменеджера, рекомендуется изучить официальную документацию.

В рамках системы алертинга, сервис mayday создает новый маршрут(route) в конфигурации алертменеджера для каждого нового правила алертинга. Когда алертменеджер отправляет алерт, в качестве способа отправки используется webhook, а в качестве адресата - сервис mayday (вебхук прилетает в контроллер). Mayday на основе содержимого вебхука определяет получателся алерта и "прокидывает" его дальше, предварительно преобразовав в нужный формат - в данный момент единственным получателем является сервис alert-tg-bot.

API, через которое происходит взаимодействие сервиса mayday с alertmanager, описано в разделе prometheus-operator.

Prometheus-operator

Сервис "общается" с prometheus'ом и alertmanager'ом через API, которое предоставляет prometheus-operator.

В случае с prometheus, mayday создает одну группу правил (RuleGroup) с именем mayday-managed-rule. Далее, при получении запроса на создание алерта, внутри этой группы создается отдельное правило на каждый алерт. Реализацию этой логики можно изучить в коде клиента prometheus.

В случае с alertmanager, mayday создает одну конфигурацию алертменеджера (AlertmanagerConfig) с именем mayday-managed-config. Далее, при получении запроса на создание алерта, внутри этой конфигурации создается отдельный маршрут на каждый алерт. Реализацию этой логики можно изучить в коде клиента alertmanager.

Конфигурации алертов

Алерты, которые поддерживает система алертинга, описаны в виде json-конфигураций и хранятся тут. Рассмотрим одну из таких конфигураций (в урезанном виде):

{
  "id": "payment_conversion",
  "readable_name": "Конверсия платежей",
  "prometheus_query": "round(100 * sum(sum_over_time(ebm_payments_final_status_count{provider_id=~\"${provider_id}\", terminal_id=~\"${terminal_id}\",shop_id=~\"${shop_id}\",status=\"captured\"}[${conversion_period_minutes}m])) / sum(sum_over_time(ebm_payments_final_status_count{provider_id=~\"${provider_id}\",terminal_id=~\"${terminal_id}\",shop_id=~\"${shop_id}\",status=~\"captured|failed\"}[${conversion_period_minutes}m])), 1) ${boundary_type} ${conversion_rate_threshold}",
  "alert_name_template": "Конверсия платежей по провайдеру '${provider_id}', терминалу '${terminal_id}' и магазину '${shop_id}' за последние ${conversion_period_minutes} минут ${boundary_type} ${conversion_rate_threshold}%",
  "alert_notification_template": "Конверсия платежей по провайдеру '${provider_id}', терминалу '${terminal_id}' и магазину '${shop_id}' за последние ${conversion_period_minutes} минут ${boundary_type} ${conversion_rate_threshold}%! Текущее значение: {{ $value }}%",
  "parameters": [
    {
      "id": 1,
      "substitution_name": "provider_id",
      "readable_name": "Введите идентификатор провайдера (опционально)",
      "mandatory": false,
      "multiple_values": true,
      "dictionary_name": "providers"
    }
  ]
}
Поле Описание
id Уникальный идентификатор алерта
readable_name Название алерта. Выводится пользователю, когда он хочет увидеть доступные к созданию алерты
prometheus_query Запрос в прометеус, который будет выполнятся в рамках alerting rules. Запрос в конфигурации содержит переменные (в формате ${variable_name}), которые заменяются реальными значениями
alert_name_template Шаблон с названием уже созданного алерта. Выводится пользователю, когда он хочет увидеть свои созданные алерты
alert_notification_template Шаблон алерта. Это сообщение присылается пользователю, когда срабатывает алерт
parameters Массив параметров, которые должен задать пользователь, чтобы mayday смог создать алерт

Каждый параметр состоит из набора полей:

Поле Описание
id Уникальный числовой идентификатор параметра. Служит для сортировки параметров (чтобы они гарантированно выводились пользователю в определенном порядке).
substitution_name Название переменной, в которое будет подставляться значение, которое передал пользователь. Значение подставляется в поля prometheus_query, alert_name_template, alert_notification_template описанные выше
readable_name Название параметра. Выводится пользователю, чтобы он понял, какая информация от него требуется
mandatory Флаг обязательности параметра. Если false, то пользователь может не вводить этот параметр
multiple_values Флаг, определяющий, поддерживает ли параметр несколько значений
dictionary_name В случае, когда пользователь не должен вводить значение параметра, а должен выбрать его из списка значений, в данном поле указывается название справочника. Поддерживаемые справочники описаны здесь
regexp В случае, когда пользователь должен вводить значение параметра, здесь указывается регулярное выражение, с помощью которого можно провести валидацию ввода

Thrift

Взаимодействие с сервисом осуществляется через протокол. Протокол реализует класс AlertingService.

Запуск и отладка сервиса на локальной машине

Для запуска сервиса на локальной машине требуется следующее:

  1. Запустить k8s. Например, в рамках Docker Desktop: Settings -> Kubernetes -> Enable Kubernetes docker_k8s.png
  2. Выполнить все шаги разделов Getting started и Alerting. В результате на вашей машине будет локально работающий кластер k8s с установленным оператором прометеус и работающей связкой prometheus + alertmanager.
  3. Запустить сервис mayday (прямо из IDE)

Готово. Теперь можно отлаживать работу сервиса с помощью woorl'а.

Примеры запросов:

Получить список поддерживаемых алертов:

woorl -s /mayday-proto/proto/mayday.thrift 'http://localhost:8022/mayday' AlertingService GetSupportedAlerts

Получить алерты пользователя:

woorl -s /mayday-proto/proto/mayday.thrift 'http://localhost:8022/mayday' AlertingService GetUserAlerts '"username"'

Удалить алерт пользователя:

woorl -s /mayday-proto/proto/mayday.thrift 'http://localhost:8022/mayday' AlertingService DeleteAlert '"username"' '"323de93494df90733484f94f1afd2b44"'

Создать алерт:

woorl -s /mayday-proto/proto/mayday.thrift 'http://localhost:8022/mayday' AlertingService CreateAlert 
    '{
    "alert_id": "payment_conversion",
    "parameters": [
    {
    "id": "1",
    "value": "(1) test_provider"
    },
    {
    "id": "1",
    "value": "(2) test_tete"
    },
    {
    "id": "1",
    "value": "-"
    },
    {
    "id": "2",
    "value": "-"
    },
    {
    "id": "3",
    "value": "(test_shop) shop details"
    },
    {
    "id": "4",
    "value": "Меньше порогового значения"
    },
    {
    "id": "5",
    "value": "50"
    },
    {
    "id": "6",
    "value": "60"
    },
    {
    "id": "rule_check_duration_minutes",
    "value": "5"
    },
    {
    "id": "alert_repeat_minutes",
    "value": "60"
    }
    ],
    "user_id": "username"
    }'