Метрики и Prometheus: типы и кардинальность
Поднял настоящий Prometheus - систему, которая собирает и хранит метрики, - и приложение, которое эти метрики отдаёт. Метрика тут это число, которое сервис регулярно сообщает о себе: сколько запросов обработал, сколько ошибок, сколько занято памяти. Одна нормальная метрика «сколько запросов» с меткой статуса (метка - это приписанная к метрике пара «имя и значение») дала 2 ряда данных. Вторая, где я по глупости положил в метку идентификатор пользователя, - 500 рядов. Всего в базе стало 1107 рядов, и сам Prometheus занял 79 мегабайт памяти. Пятьсот пользователей - это ещё маленький сервис.
Стержень: метрики собираются опросом, а стоимость хранения определяется не числом метрик, а числом сочетаний меток.
// Формулировки: «почему Prometheus сам ходит за метриками?», «чем счётчик отличается от измерителя?», «что такое кардинальность и чем она опасна?»
Кто к кому ходит
Prometheus не ждёт, пока приложение что-то пришлёт. Он сам по расписанию (у меня раз в 5 секунд) ходит на адрес приложения и забирает текущие значения. Это называют моделью опроса, и у неё есть приятный побочный эффект: сам факт удачного опроса - уже метрика. Она называется up и равна единице, если опрос прошёл.
Проверил, что бывает при падении цели. Пока приложение живо, up равна 1. Я остановил контейнер - через несколько секунд up стала 0, и это готовый сигнал «сервис недоступен», который не надо специально придумывать. А вот сами метрики приложения из запросов ПРОПАЛИ: не замерли на последнем значении, а именно перестали возвращаться. Это важно: график не «застывает», он обрывается.
// Обратная сторона модели опроса - недолговечные задачи. Скрипт, который живёт 200 миллисекунд, опросить невозможно: к моменту прихода Prometheus его уже нет. Для таких случаев ставят промежуточный приёмник, куда задача сама отправляет результат перед смертью, а Prometheus опрашивает уже его.
- модель опроса
- сборщик сам ходит за метриками по расписанию
- метрика up
- 1, если опрос цели удался; готовый сигнал недоступности
- промежуточный приёмник
- место, куда короткоживущие задачи кладут метрики перед смертью
Счётчик, измеритель и гистограмма
Счётчик только растёт. У меня «всего запросов» показал 21 564 успешных и 899 ошибок. Само по себе это число бесполезно: оно накопилось с момента запуска. Смысл появляется от скорости роста - я посчитал её и получил 345,5 запроса в секунду и 14,5 ошибки в секунду.
Измеритель может расти и падать: это мгновенное значение вроде «запросов прямо сейчас в обработке» (у меня 10) или «свободно памяти». Его читают как есть, скорость роста для него бессмысленна.
// Гистограмма - счётчики попаданий в корзины по длительности. У меня стояли корзины 0,005, 0,01, 0,025, 0,05, 0,1, 0,25, 0,5, 1, 2,5 и 5 секунд плюс «всё остальное». Из неё считаются квантили - значения, ниже которых лежит заданная доля запросов, - но считаются по корзинам, а не по точным значениям, и это накладывает ограничения, о которых отдельно.
// И ещё один важный факт про счётчики, который я проверил специально. Приложение перезапустилось - счётчик начался с нуля (у меня 3821 вместо 21 564). Сырое значение при этом «упало», а вот скорость роста осталась правильной, 316 в секунду: функция расчёта скорости умеет замечать сброс счётчика и не считает его отрицательным всплеском.
- счётчик
- только растёт; смысл имеет его скорость роста, а не само значение
- измеритель
- мгновенное значение, может расти и падать
- гистограмма
- счётчики попаданий в корзины; из неё считают квантили
Кардинальность: чем платят за красивые метки
Ряд данных в Prometheus - это уникальное сочетание имени метрики и всех её меток. Метрика с меткой статуса на два значения даёт 2 ряда. Та же метрика с меткой идентификатора пользователя даёт столько рядов, сколько было пользователей: в моём замере 500 при пятистах пользователях, ровно один к одному.
Дальше умножение. Добавили метку с адресом клиента - плюс тысячи. Добавили путь запроса, а в нём номер заказа - плюс миллионы. Каждый ряд занимает память в текущем срезе и место на диске, а запросы по ним замедляются. У меня 1107 рядов держали 79 мегабайт, и это игрушечный стенд.
// Правило простое: в метках живут ЗАКРЫТЫЕ множества. Статус, метод, код ответа, имя сервиса, зона - у них конечное и небольшое число значений. Идентификаторы пользователей, заказов, сессий, полные пути с числами - в метки не кладут никогда. Если такая детализация нужна, для неё есть логи и трассировки, где стоимость устроена иначе.
- ряд данных
- уникальное сочетание имени метрики и всех её меток
- кардинальность
- число таких сочетаний; растёт умножением значений меток
Как отвечать: «Что такое кардинальность метрик и чем она опасна?»
Кардинальность - это число рядов данных, а ряд это уникальное сочетание имени метрики и всех её меток. Опасность в том, что метки перемножаются, и растёт всё очень быстро. Я это специально мерил на стенде: обычная метрика с меткой статуса дала 2 ряда, а та же метрика с идентификатором пользователя в метке - 500 рядов при пятистах пользователях, один к одному. На реальном сервисе это миллионы рядов, каждый из которых занимает память в текущем срезе и место на диске, а запросы по ним замедляются. Правило, которым я пользуюсь: в метки идут только закрытые множества - статус, метод, код ответа, имя сервиса. Идентификаторы, полные пути с номерами и адреса клиентов туда не кладут никогда, для такой детализации есть логи и трассировки.
Ответ даёт определение, показывает механику умножения на измеренном примере и заканчивается правилом, по которому можно принимать решения. Это разговор человека, который чинил взорвавшийся сборщик.
На чём валятся
- −Кладут в метки идентификаторы пользователей и заказов и взрывают хранилище.
- −Читают сырое значение счётчика вместо его скорости роста.
- −Ждут, что метрики упавшего сервиса «замрут» на последнем значении. Они пропадают.
- −Пытаются опрашивать короткоживущие задачи вместо промежуточного приёмника.
- −Считают, что счётчик после перезапуска сломает график. Расчёт скорости умеет замечать сброс.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 7, остальные разбираются в тренажёре.
- В метрику запросов добавили лейбл с идентификатором пользователя. Через сутки Prometheus упал по памяти. Почему?A)Лейблы со строками не поддерживаются и ломают формат храненияB)Каждое значение лейбла порождает отдельный временной рядC)Скрейп стал медленнее и очередь запросов переполнила памятьD)Идентификаторы попали в индекс логов и раздули хранилище
показать ответ и разбор
+B)Каждое значение лейбла порождает отдельный временной ряд// разбор: Временной ряд определяется именем метрики и полным набором пар лейблов. Идентификатор пользователя даёт столько рядов, сколько пользователей: сотни тысяч серий, каждая со своим индексом и буферами в памяти. Отсюда правило: в лейблы кладут только значения с малым и предсказуемым числом вариантов — сервис, метод, код ответа. Всё уникальное (идентификаторы, урлы с параметрами, трейсы) живёт в логах и трассах.
- Нужно снимать метрики хоста (CPU, диск, память), но сам сервис их не отдаёт. Как получить их в Prometheus?A)Prometheus сам собирает системные метрики хостаB)Поставить экспортёр (node_exporter), Prometheus скрейпит егоC)Слать метрики хоста в Prometheus по syslogD)Читать /proc напрямую из правил Prometheus
показать ответ и разбор
+B)Поставить экспортёр (node_exporter), Prometheus скрейпит его// разбор: Prometheus работает по pull: скрейпит HTTP-эндпоинт /metrics. Если источник сам метрики не отдаёт (ОС, БД, железо), ставят экспортёр — отдельный процесс, который снимает показатели и публикует их в формате Prometheus (node_exporter для хоста, postgres_exporter и т.д.). Prometheus скрейпит экспортёр как обычную цель. Своего сбора из /proc или приёма по syslog у него нет.
- Для задержки ответа выбирают между summary и histogram. Почему для агрегируемых по кластеру квантилей берут histogram?A)Histogram копит бакеты и агрегируетсяB)Summary точнее, но занимает больше места на дискеC)Histogram отдаёт готовый квантиль без вычисленийD)Summary для измерения задержки не годится
показать ответ и разбор
+A)Histogram копит бакеты и агрегируется// разбор: summary вычисляет квантили на стороне клиента, для каждого инстанса свои — а такие готовые квантили нельзя корректно усреднять/суммировать по кластеру. histogram копит наблюдения по бакетам (счётчики), которые складываются между инстансами, и итоговый квантиль считают из суммарных бакетов через histogram_quantile. Поэтому для общекластерных p95/p99 берут histogram; summary — когда квантиль нужен локально и агрегация не важна.
- Короткая batch-джоба выполняется секунды и завершается. Prometheus не успевает её заскрейпить. Как снять её метрики?A)Уменьшить scrape_interval до долей секундыB)Джоба должна сама слать метрики прямо в TSDB PrometheusC)Держать джобу живой ещё минуту после завершенияD)Через Pushgateway: джоба пушит метрики, Prometheus скрейпит шлюз
показать ответ и разбор
+D)Через Pushgateway: джоба пушит метрики, Prometheus скрейпит шлюз// разбор: Pull-модель не годится для короткоживущих задач: процесс исчезает раньше, чем Prometheus придёт скрейпить. Для них Pushgateway: джоба по завершении пушит свои метрики в шлюз, а Prometheus скрейпит уже шлюз. Осторожно: Pushgateway хранит последнее пушнутое значение (метрики не «тают» сами — нужна очистка), и это не способ превратить Prometheus в push-систему для обычных сервисов.
- Что такое метрика в мониторинге?A)Числовое измерение во времениB)Текстовая запись о событии в приложенииC)Порог, при достижении которого шлют оповещениеD)Отчёт о работе сервиса за прошедший месяц
показать ответ и разбор
+A)Числовое измерение во времени// разбор: Метрика это ряд чисел с отметками времени: число запросов, занятая память, длина очереди. Числа дёшево хранить и агрегировать — потому по метрикам строят графики и алерты, а подробности ищут уже в логах.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.