Clickhouse & Grafana: история успеха одних алертов

Привет, Хабр!

Меня зовут Елизавета Добрянская и я фронтенд-разработчица в компании Домклик.

Я хочу рассказать, как мы танцевали с бубном при настройке алертов на клиентские метрики. Как, зачем и с чем мы столкнулись в этой задаче — читайте дальше 🙂

О чём эта статья

Несколько слов про Clickhouse и Grafana, чтобы было понятно, о чём дальнейший разговор.

Clickhouse — столбцовая система управления базами данных (СУБД) для онлайн-обработки аналитических запросов. Мы используем её для сохранения метрик о пользовательских действиях на сайте (клики по ключевым кнопкам, открытие экспериментальных страниц и т.п.). Она предоставляет удобный интерфейс для отправки данных прямо из нашего клиентского кода, что нас более чем устраивает.

Grafana — платформа для визуализации, мониторинга и анализа данных. Она позволяет строить графики по собранным метрикам, реагировать на внештатные ситуации, визуально проверять гипотезы и многое другое. Одной из весомых функций этой платформы является автоматическая рассылка алертов. Во многом из-за неё появилась эта статья.

Зачем нам такие специфичные алерты

Кажется, обработка метрик — это исключительно бизнес-история и она не должна напрямую затрагивать разработчиков. К сожалению, всё не так просто. Продукт — это полноценная машина, в которой всё взаимосвязано. Разработчики влияют на сбор метрик так же сильно, как на выкатку новой фичи. Почему? Потому что и новая функциональность, и отправка метрик работают через один и тот же программный код. И если мы катим новый релиз, нам важно проверить не только работоспособность нашего проекта, но и корректную отправку метрик. Думая над решением этой проблемы, мы пришли к выводу, что наконец-то настал тот день, когда мы сделаем алерты на метрики.

Мы решили обеспечить бесперебойную доставку метрик с фронта в Clickhouse. Для проверки этой доставки наиболее удобным инструментом для нас стала Grafana, потому что у нас уже есть графики по метрикам, плагин для работы с Clickhouse и чатик алертов в Telegram. Звёзды сошлись 💫

Механизм работы алертов

Как определить «потерю метрик»? Очень просто: потерянные метрики перестают сохраняться в Clickhouse, а значит график их отображения в единицу времени стремительно приближается к нулю.

То есть достаточно собирать метрики за единицу времени и слать алерт, если они равны нулю? Не совсем так. Сбор количества, к примеру, за час может привести к тому, что алерты стрельнут ночью (потому что ночью трафик очень близок к нулю), а это некорректный результат. Поэтому механизм был переделан на более динамичный и менее привязанный к времени суток.

Мы решили проверять резкие изменения графика. В текущий момент времени смотрим, насколько изменилось текущее количество метрик относительно количества 10 минут назад. Берём это изменение в процентах. Считаем нормой, если изменение составляет больше 10 %. Если меньше 10 % — шлём алерт. Для проектов, которые обычно редко открывают, оцениваем изменение за более длинный период (например, за час). Получается более сглаженная метрика, к тому же после выкатки проекта можно быстро заметить, если метрики «отвалились».

Еще нюанс. «Количество в текущий момент времени» — это не в текущую минуту. Прямо в текущую минуту метрики не успевают дойти до Clickhouse. Поэтому для чистоты сбора считаем «текущим временем» момент минуту назад (или час назад для редких метрик).

Базовая настройка алертов в связке Grafana + Clickhouse

Теперь разберём подробнее, куда нажимать и что за что отвечает.

Шаг 0. Настроить окружение в Grafana

У нас этот шаг был выполнен ещё админами, поэтому нам не пришлось. Но если вы настраиваете с нуля, то придётся это сделать:

  • создать пространство команды;

  • создать новый дашборд;

  • добавить новый ресурс данных для Clickhouse (Configuration → Data Sources → Add data source);

  • добавить пользователя для подключения к Clickhouse из Grafana;

  • добавить новый канал для отправки алертов (Alerting → Notification channels → New channel).

Шаг 1. Настраиваем график метрик

Мы прописывали два разных запроса (Query). Один строит график, который мы можем проверить «глазами» на дашборде, а второй высчитывает необходимое значение для генерирования алертов.

В этом шаге разберём первый запрос. Выбираем нужные нам базу данных, таблицу и формат (здесь важно, чтобы был Time Series, иначе график не построится), а затем пишем само тело запроса. «По-старинке» на SQL:

SELECT toStartOfMinute(created_at) as time, uniqIf(user_id, event_type = 'page_view') as show_metric
FROM $table
WHERE app_id = 999 AND $timeFilter
GROUP BY time
ORDER BY time
LIMIT 15

Небольшие пояснения по коду.

Это не чистый SQL, а с примесями Clickhouse. Об этом вы можете почитать в документации, ссылка прикреплена внизу. В качестве примесей здесь выступают:

  • переменные (макросы) $table и $timeFilter, которые позволяют обратиться к данным из текущей страницы Grafana. $table — это наша таблица, которую мы указали при создании запроса, а $timeFilter — временной интервал, который мы выбрали в выпадающем меню интерфейса Grafana (правый верхний угол детализации графика).

  • функции агрегации. toStartOfMinute — группируем таймстемпы, произошедшие в одну и ту же минуту, uniqIf — берём количество уникальных пользователей, увидевших нашу метрику

Не забываем указывать фильтрацию $timeFilter, чтобы не нагружать Clickhouse лишними запросами.

После этих нехитрых манипуляций у нас должен построиться график получения метрики page_view в минуту. Круто! Пошли настраивать алерты.

Шаг 2. Настраиваем запрос для алертов

Для алертов пишем второй запрос, который не будет отображаться на графике, а будет использоваться только для проверки алертов. Запрос возвращает число — это процент, на который изменился график за последние 10 минут. Он очень похож на предыдущий запрос, но немного сложнее, потому что нам нужно взять процентную разницу между двумя временными точками.

Заметка: на самом деле этот запрос должен вернуть временной интервал (Time Series), иначе алерты работать не будут. Поэтому к нашему результату мы подмешиваем текущую временную метку.

Итак, код этого безобразия выглядит как-то так (слабонервным не смотреть):

SELECT now(), ROUND(count_current / count_10m_ago * 100, 2) as diff_in_percent
FROM ( SELECT uniqIf(user_id, event_type = 'page_view') as count_current FROM $table WHERE app_id = 999 AND toStartOfMinute(created_at) = toStartOfMinute( dateadd(minute, -1, now()) ) LIMIT 60
) current, ( SELECT uniqIf(user_id, event_type = 'page_view') as count_10m_ago FROM $table WHERE app_id = 999 AND toStartOfMinute(created_at) = toStartOfMinute( dateadd(minute, -11, now()) ) LIMIT 60
) old

Как и было сказано выше, он состоит из трёх частей:

  • получение текущего количества метрик (первый подзапрос SELECT);

  • получение количества метрик 10 минут назад (второй подзапрос SELECT);

  • подсчёт изменения количества метрик, перевод в проценты (верхний SELECT).

Круто, запрос есть. Можем перейти к самой настройке.

Шаг 3. Настройка алертов в Telegram-канал

Дальнейшая настройка сводится к простым манипуляциям с Grafana и выбору правильных настроек под конкретный случай. У нас это выглядит так:

Настройка алерта.
Настройка алерта.
  • Name — название алерта, которое будет фигурировать в сообщении в канале.

  • Evaluate every — интервал оценки (с какой частотой проверяется правило алерта).

  • For — время, в течение которого мы считаем ситуацию неизменной.

  • WHEN — выбираем агрегирующую функцию.

  • OF — query (B, 10m, now) — проверяем запрос B в диапазоне [сейчас, 10 минут назад].

  • IS BELOW — выбираем функцию сравнения («меньше») и указываем число 10 (10 процентов).

Из интересного ещё можно настроить ситуации с ошибками и восстановлением. Мы оба поля ставим в Keep Last State, чтобы не получать алерты в этих случаях.

После всех настроек проверяем работу алерта. Нажимаем кнопку Test rule. Появляется модалка, где важно проверить, что нет ошибок. Если всё верно настроено, будет показана ситуация:

Проверка работы алерта.
Проверка работы алерта.

Ура, у нас есть алерты на метрики!

Что пошло не так?

Вся вышеописанная история выглядит очень красиво и просто, да? На самом деле процесс был не таким радужным. Поэтому теперь пришло время «жаришки» — поговорим о том, на что стоит обратить внимание при настройке похожих алертов и что мы хотели бы знать, прежде чем лезть в это.

1. Чувствительная Grafana

Работу с Grafana можно сравнить с походом в дорогой ресторан: ожидаешь попробовать нечто изысканное, а по итогу высокая кухня оказывается «на любителя», и мамины котлеты всё равно вкуснее. Ты пытаешься работать с дашбордами аккуратно и планомерно, а ошибки стреляют в тысяче разных мест просто так.

Итак, чеклист по «нежной» работе с Grafana:

  • Параллельная работа здесь невозможна. Над панелью (или даже над всей бордой) лучше работать только одному человеку и только в одной вкладке. Иначе что-то где-то не сохранится и придётся заново настраивать.

  • Постоянно надо сохранять. Каждое своё изменение на борде. Представьте, что вы работаете в старом Microsoft Office.

  • Постоянно надо перепроверять. После сохранения лучше зайти и проверить, что всё действительно сохранилось

  • Непонятные логи. Готовьтесь к тому, что вы не поймёте логи ошибок с первого раза и будете чинить их наугад. Grafana выдаёт лог ошибки напрямую из Clickhouse, причём он обернут в JSON с дополнительной информацией. Чтобы это всё обуздать, надо быть мастером Шифу, но это не точно.

2. Нестабильность Clickhouse

Это касается не столько разработки, сколько администрирования Clickhouse в компании. К сожалению, профилактические работы могут очень сильно повлиять на наши алерты. Любые накатывания обновлений или просто приостановка сервиса вызывает падение метрик в ноль из-за недоступности. И мы получаем алерты. Не смертельно, но грустно. И повод задуматься: а надо ли вам вообще всё это?

3. Нехватка информации о настройке стека

Этот пункт, пожалуй, мой любимый. Готовьтесь к тому, что загуглить ошибки не получится, и заложите х3 времени на задачу. Во Всемирной паутине очень мало информации о работе связки Grafana + Clickhouse. Пожалуй, наиболее достоверными источниками здесь остаются только документации сервисов и плагина. Если недостаточно этого, то issues и networking.

4. «У вас не последняя версия!»

Продолжение пункта 2. Время историй. Прежде, чем я взялась за задачу в эксплуатации, я подумала, что вполне хорошей идеей будет разобраться с алертами на локальной машине. Скачала Grafana, поигралась с настройками, написала скрипты и даже настроила какие-то алерты, порадовалась. Потом с огромным энтузиазмом и ощущением, что задача успешно выполнена, я пошла в прод. И оказалось, что версии Grafana в нашем проде и на моей локалке разные. И это колоссально, потому что никакие мои скрипты не заработали, и по сути пришлось делать задачу с нуля.

Мораль: тестируйтесь в том же окружении, в котором будете работать.

Мораль 2: будьте готовы, что когда-нибудь версии обновят, и вы об этом узнаете, когда у вас отвалятся метрики.

5. Разница в версиях. Продолжение

Что же ломается в проде? Одной из самых значимых проблем стал Time Series, а именно работа с временными метками. В последней версии Grafana весь код, приведённый выше, работает прекрасно. Но в проде у нас (на момент на писания статьи) не последняя версия! Поэтому легким движением руки временная ветка превращается из

toStartOfMinute(created_at) as time

в

toUnixTimestamp(toStartOfMinute(created_at), 'UTC')*1000 as time

Вопрос во Вселенную: как я должна была догадаться до этого преобразования?! 🙂

6. «Переобувание» алгоритма

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

Исходя из того, что алертов мы так и не дождались, пришлось импровизировать и придумывать новый алгоритм. И кажется, это к лучшему ✨

Итоги

Забавно, что современный фронтенд-разработчик сильно выигрывает, если умеет больше, чем просто красить кнопочки. Это открывает перед нами гораздо больше возможностей разрабатывать удобные и полезные продукты. Но прежде, чем внедрять что-то новое, нужно крепко подумать: а нужно ли вам это?

Буду рада, если наш опыт вам полезен. Всем хорошего веба ✌🏻

Вместо послесловия. Полезные ссылки

Читайте так же:

  • Ложные друзья переводчика: 15 английских слов и фраз, которые не нужно переводить буквальноЛожные друзья переводчика: 15 английских слов и фраз, которые не нужно переводить буквально Сегодня мы расскажем вам о главном неприятном сюрпризе для студента, который начинает изучать иностранный язык. Словарный запас еще небольшой, а тут встречается слово, которое сильно похоже на знакомое. К примеру, accurate. Человек сразу думает, что это «аккуратный». Ведь не может […]
  • Небинарный ngIf*Небинарный ngIf* Вам когда-нибудь хотелось отобразить состояние загрузки, пока ngIf ждет ответа от async-пайпа? Или, может, вы мечтали передать в ngFor шаблон для пустого массива? Возможно, вы бросили это, потому что вам не хотелось реализовывать базовую логику этих директив самому. На самом деле в этом […]
  • Snap впервые показала прибыльSnap впервые показала прибыль Компания Snap опубликовала финансовый отчет за 2021 год. В документе компания сообщила о квартальной прибыли в размере 23 млн долларов, но это не повлияло на итоги года. За 2021 год компания зафиксировала чистый убыток в 448 млн долларов. Snap, владеющая мессенджером Snapchat, вышла на […]
  • Продвижение во ВКонтакте, Instagram и Facebook: что нужно знать специалисту Описание 14 — 16 июня научим бесплатно продвижению во ВКонтакте, Instagram и Facebook.Хотите прокачать свои скиллы, увеличить доход и получить мощную обратную связь в прямом эфире? Подключайтесь!Программа интенсива:14 июня мы подготовимся к запуску рекламы в Instagram, Facebook […]