Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Однажды мне понадобилось внедрить метрики в сервисы своей команды. С самого начала я не понимал, что именно хочу получить: одно дело — прикрутить библиотеку и нарисовать графики, другое дело — показывать осмысленные данные.
Мне нужен был гайд, который сочетает эти две вещи: сначала «почему так принято», а затем — «как правильно делать». В результате такой гайд мне пришлось написать самому. Его цель — объяснить разработчикам с любым бэкграундом, что такое метрики, как правильно о них думать и осмысленно использовать. Сначала гайд жил во внутренней документации Точки, но я решил сделать его публичным — возможно, кому-то этот опыт будет полезен. Разбираться будем с Prometheus и Grafana. Если у вас другой стек — не страшно. Мы затронем и фундаментальные темы: например, перцентили, производные и кардинальность.
Гайд будет выходить как цикл статей. Сначала посмотрим на архитектуру: как собираются метрики и где хранятся. Дальше разберемся с типами метрик — они не так просты, как кажется. Потом придется немного отвлечься на математику (но только с инженерной точки зрения!). И, наконец, научимся писать запросы, но не просто так: сразу посмотрим на разные грабли и неочевидные моменты.
Какие статьи выйдут в цикле:
Потерянное введение
Prometheus
Перцентили для чайников
PromQL
Прежде чем подключать библиотеки, поднимать сервера и писать запросы, давайте восстановим справедливость и найдем введение, которого мне не хватило при изучении метрик. В этой статье мы определимся, какую вообще решаем задачу, и почему решение такое непривычное.
Здравый смысл
Вот захотели вы собирать разные метрики, «чтобы было видно все, что происходит в сервисах». Теперь задайте себе и команде важные вопросы:
А как это вообще сделать?
А что именно хочется увидеть в результате?
Как решают эту задачу другие люди?
Чтобы не придумывать свой велосипед, можно изучить общепринятые подходы, найти готовый стек. Но там будет, что называется, своя атмосфера. И нет коллеги или гайда, которые бы объяснили, почему оно вообще так странно устроено.
Технически задача выглядит как-то так: в компании уже есть, например, Grafana (если нет, ее несложно поднять). Есть сотня способов собрать и передать туда данные, но сразу возникают вопросы: что мы хотим там отобразить? А почему нельзя это просто в SQL сложить? Зачем нужен этот ваш Prometheus, наконец?
Для сложных технологий хорошо иметь не только инструкцию, но и правильный mindset, тогда все инструменты будут даваться легче.
Вот со всем этим и будем разбираться.
Вообще метрики — это неожиданно сложно: мы пытаемся разными инженерно-математическими фокусами сжать неудобный, большой массив данных до чего-то наглядного. В отличие от логов, которые просто пишутся «как есть» и наверняка уже используются в ваших сервисах. Кстати, а почему бы не парсить логи и на основании этого уже строить какие-то графики? Так, конечно, можно, и это нормально — до некоторого предела.
Метрики vs логи
Логи — это про точность: мы собираем информацию на каждое событие. Если их агрегировать, можно увидеть общую картину и даже вытащить детали вплоть до единичного запроса. Но отправка логов на каждый чих плохо масштабируется.
Трафик логов зависит от трафика приложения: больше запросов, больше действий – и логов пропорционально больше. Часто они не структурированы, их сложно индексировать и парсить — для графиков нужно вытаскивать числа из текста. Ну и традиционно в логи пишется много лишнего, а значит обработка и агрегация будут страдать и отставать от реального времени.
Метрики – это сразу общая картина о состоянии приложения. Мы собираем не все детали, а только готовую выжимку: например, количество запросов к сервису. Картину мы получим, но в детали провалиться нельзя. Зато такой подход хорошо масштабируется и быстро работает. Можно моментально реагировать и рассылать алерты. Если нужны детали – думаем и добавляем по чуть-чуть.
Например, считаем количество запросов к разным endpoint-ам. Трафик метрик зависит от их количества и периодичности сбора/отправки их в хранилище. И, наконец, в метрики мы не пишем ничего лишнего, а, наоборот, стараемся писать как можно меньше. В следующих частях станет понятно, почему.
Пишем все и потом думаем (ценой трафика и сложности обработки) vs думаем и пишем только, что надо (ценой потери деталей).
Если у вас не очень много сервисов, и вы не планируете масштабирование, то можно не усложнять и остановиться на парсинге логов. В популярном стеке ELK есть встроенные средства визуализации.
Push vs Pull
Сбор метрик можно организовать двумя способами. У каждого есть свои плюсы и минусы. Чем глубже копать и чем больше масштабы, тем сложнее становится выбор — вплоть до холиваров.
Push – принцип такой же, как с логами или базой данных: произошло событие – пишем данные в хранилище. События можно отправлять пачками. Способ прост в реализации с точки зрения клиента.
Pull – наоборот: приложения хранят в памяти компактные данные вроде обработано запросов: 25
. Кто-то периодически приходит и собирает их, например по HTTP. С точки зрения клиента pull сложнее реализовать, но проще отлаживать: у каждого приложения появляется endpoint, куда можно зайти браузером и увидеть, что происходит конкретно в этом приложении. Не нужно писать хитрые запросы, фильтровать данные по репликам и вообще иметь доступ в общее хранилище метрик. Кроме того, эта модель стимулирует разработчиков писать в метрики только то, что необходимо, а не все подряд.
Чтобы метрики не занимали лишнюю память приложения и быстро отдавались, мы вынуждены их агрегировать. Никто не хочет хранить в памяти подробности о каждом запросе, потому что эти данные очень быстро займут всю память. Приходится ограничиваться минимумом: например, вести счетчики запросов и ошибок. Это в итоге уменьшает нагрузку на инфраструктуру: ей нужно забрать и сохранить уже максимально сжатые данные, о которых уже подумали разработчики приложения.
Конечно, push тоже можно приготовить аналогичным образом, но там гораздо проще отправлять все подряд, а потом разбираться.
Мы выбрали pull: Prometheus на тот момент был построен в основном вокруг этой модели, и нам было проще выбрать решение с централизованным управлением.
TSDB
Метрики нужно куда-то складывать и потом делать выборки. Эту задачу решают специализированные БД: Time Series Database.
Особенности TSDB – обработка временны́х рядов, то есть однотипных измерений во времени. БД этого типа оптимизируют хранение какого-то числа, которое записано через равные интервалы времени. Проще понять на примере: чтобы собирать ежедневную температуру воздуха, нам надо хранить что-то вроде [(day1, t1), (day2, t2), ...]
и больше ничего.
Главное сейчас – понять вот эту особенность: TSDB нужны, чтобы сохранять время и одно число, привязанное к этому времени. Потом снова время и число, и так далее. Пока что обойдемся без конкретики и деталей реализации.
Специфика:
реляционку умеют по минимуму: если SQL, то ограниченный, а то и вовсе его нет
типы хранимых данных урезаны
оптимизация на постоянную непрерывную запись
Раз на SQL это все не похоже, то не обязательно поддерживать сложный язык запросов. Можно сделать свой, упоротый метрико-ориентированный простой язык.
Когда-то мы использовали для метрик InfluxDB — у него как раз SQL-подобные запросы. Но на наших объемах он просто взорвался, и с high availability было плохо, поэтому от него отказались.
Для работы с TSDB существуют свои специализированные форматы данных, и они проще, чем SQL. В следующей части мы разберемся, как готовить TSDB Prometheus: он устроен так, что формат метрик и язык запросов — это практически одно и то же, поэтому страдать придется всего один раз!
Визуализация
Когда у нас появится БД для хранения метрик и способ доставки данных в нее, мы сможем писать запросы, но... Просто так смотреть на таблицы с числами неинтересно. Поэтому запросы к БД обычно делает Grafana: она парсит таблицы из ответов и рисует удобные графики. В ней уже можно настроить масштаб, покрасить и добавить прочие украшения. Но писать запросы все равно придется самостоятельно.
Дальше мы будем разбираться именно с запросами Prometheus, без нюансов, которые добавляет Grafana. Поэтому для начала она вообще не понадобится — у Prometheus есть простой web-интерфейс, который визуализирует результаты запросов. Его вполне хватит для обучения, тестов и отладки.
Алерты
Самое полезное, что можно выжать из метрик и графиков – это алерты: нам не нужен живой человек, который постоянно следит за свободным местом на диске или за количеством ответов HTTP 500
. Можно настроить автоматику, которая реагирует на выход графиков за допустимые границы и рассылает уведомления. Но, чтобы до этого добраться, придется сначала научиться собирать и хранить метрики, потом их запрашивать и отображать на графиках, и только потом уже расставлять алерты.
С алертами мы разбираться не будем, потому что концептуально тема уже не настолько сложная для понимания, как метрики, а архитектура решения будет очень сильно зависеть от специфики: кому-то нужна рассылка в мессенджере, кому-то телефонный бот.
Теперь должно быть более-менее понятно, из чего будет состоять решение для сбора метрик, и почему оно такое непривычное. Дальше будем разбирать формат данных и язык запросов Prometheus.