Сбор и агрегирование метрик. Часть 1
Недавно я читал доклад на golang митапе в Киеве о метриках и логах для программистов и остался собой недоволен, так как у меня не получилось высказать всё, что хотел, коротко и ёмко. Поэтому я решил написать пару статей о том, что такое метрики и statsd, и коротко рассказать о том, как и чем можно собирать метрики и какие архитектуры использовать.
Что такое statsd
Чтобы понять, что такое statsd и какие проблемы он решает, стоит понять, что такое метрика.
Метрика — это сгруппированные по ключу данные в формате значение - время.
Такой формат данных позволяет достаточно эффективно привязывать какие-либо события ко времени и впоследствии делать выборки или рисовать графики.
Обычно метрики складывают в разные специальные TSDB (time series database):
- whisper — graphite, go-carbon
- rrd — rrd-tool
- TSMT — influxdb
Или в другие бд:
- cassandra — M3, newTS, cyanite, kairosDB
- hbase — openTSDB
- LevelDB — prometheus
Метрика может представлять собой как срезы по времени (например, сколько соединений в конкретный момент времени были в состоянии ESTABLISHED), так и различные агрегации (сколько подключений было всего за период в 10 секунд)
Сами по себе агрегации тоже бывают разными. Например, популярная метрика LA является агрегацией других метрик (вот тут есть хороший разбор) и дополнительно агрегирована по периоду времени в одну, пять и пятнадцать минут. Таким образом, просто делая срезы LA раз в десять секунд, мы сможем примерно представлять динамику изменений этого параметра.
Другие метрики, такие как скорость сети, измеряются при помощи считывания счетчиков, которые уже есть в linux.
В случае пропускной способности сети мы можем посмотреть /sys/class/net/eth0/statistics/rx_bytes
или /proc/net/dev
. Значение, которое мы увидим, — некий счетчик, который увеличивается с каждый принятым байтом с начала отсчёта.
Подобный график очень сложно интерпретировать, но так как мы делаем срез через определённые интервалы, просто отнимем от левого значения правое и получим количество байтов, которые пришли за этот интервал.
Для удобства, чтобы оперировать привычными юнитами, можно ещё повыполнять различные арифметические операции деления и прийти к обычным kb\s.
Первый существенный минус такого подхода в том, что каждый раз, когда перезапускается счетчик, мы получаем большое отклонение.
Чтобы его убрать, можно использовать специальную функцию nonNegativeDerivative в графите, которая убирает все отрицательные значения.
Второй минус в том, что каждый раз при просмотре графика мы производим вычисления, без которых можно обойтись.
Логичным выходом из такой ситуации станет счетчик, который будет обнуляться в начале каждого интервала.
Но не счетчиками едиными: иногда надо посмотреть на распределение значения по времени. Особенно это актуально, если мы замеряем какое-то время.
Тут всё сложнее, так как невозможно сделать постагрегацию, если не хранить вообще все значения. Про гистограммы на примере мониторинга http я писал более-менее подробно тут.
И последний вид необратимых агрегаций — уники. Например, если вам надо посчитать, сколько уникальных юзеров получили 500 за 10 секунд.
В принципе, этими тремя типами агрегаций можно охватить все известные мне счетчики. Если вы знаете что-то, что нельзя покрыть каунтерами, сетами и гистограммами, обязательно напишите мне в комментариях, я буду очень признателен.
statsd — зачем он нужен?
После того как мы выяснили, как именно можно предагрегировать метрики, можно реализовать это всё у себя в коде. Уже есть множество разных библиотек под многие из языков программирования, самая популярная — это вариация metrics, портированная на разные языки.
Или просто использовать демон, который делает это всё за вас. У обоих вариантов есть свои плюсы и минусы, и об этом мы поговорим в следующей статье.