Сбор и агрегирование метрик. Часть 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, портированная на разные языки.

Или просто использовать демон, который делает это всё за вас. У обоих вариантов есть свои плюсы и минусы, и об этом мы поговорим в следующей статье.