Если у вас есть какая-то система мониторинга чего-то — наверняка там есть какие-то показатели, которые актуальны здесь и сейчас: для метеостанции — температура, для роутера — трафик, для сервера — нагрузка, и т.д. — в общем, какая-то актуальная величина.
Но кроме онлайн-значений — может быть полезен график, например за ближайшие сутки, или за месяц, или за год — чтобы можно было оценивать тренды.
Или наоборот: иногда происходит какое-то событие, достаточно редкое (сбой, или наоборот срабатывание устройства), но хотелось бы понимать, насколько часто, и не меняется ли его частота в разные периоды — ведь это может быть признаком более серьезной проблемы.
Самое очевидное решение — писать данные в базу.
Но такая таблица будет постоянно расти, занимать всё больше места, а выборка за прошлый период может отрабатывать довольно долго, особенно если требуется уместить целый год в 900 пикселей графика.
Когда-то и я наступил на эти грабли — когда база на MongoDB распухла так, что не влезла в 32-битный компьютер. Но это другая история.
При этом далеко не всегда нужно точно знать, какая температура была на датчике 26 июля 2016 года в 14:33:15 — чаще достаточно просто усредненных значений.
Вот как раз для подобного давным-давно люди придумали RRD — Round-robin database.
Принцип простой: кольцевой буфер фиксированной длины, новые значения записываются в него одно за другим, а когда доходят до конца — начинают записываться с начала.
Мы всегда знаем, какое значение актуально сейчас, а какое — Х времени назад, если это время не превышает длину буфера.
Более того — таких буферов может быть несколько, с разным «размером» ячейки и с разной длиной, просто за больший период будут храниться данные с меньшей детализацией.
Для работы с подобным давным-давно существует инструмент rrdtools.
Это несколько утилит, которые работают с файлами RRD, позволяя создавать их, наполнять данными, извлекать данные и даже строить графики.
Например, нужно хранить температуру — типовая, простая задача.
Сначала создаем под нее файл базы данных:
rrdtool create termo.rrd -s 60 \ DS:t:GAUGE:300:-50:U \ RRA:LAST:0.5:1:10080 \ RRA:AVERAGE:0.5:5:8064 \ RRA:AVERAGE:0.5:60:8760
Создается файл termo.rrd, шаг данных — 60 секунд.
В нем будет один «источник данных», DS, который условно называется «t», имеет тип GAUGE (измерение, показатель), для него установлен период 300 секунд, в течении которых ожидаются хоть какие-то данные, минимальное значение -50, максимальное — не определено (U).
Данные обрабатываются «как есть», температуры ниже -50 отбрасываются, если в течении периода 300 сек ничего не записано — считаем, что данных нет, nan.
При этот определены 3 буфера, RRA:
Первый состоит из слотов по 1 60-секундному периоду, в каждом слоте будет содержать последнее поступившее значение, и всего их таких — 10080 штук, итого весь период 604800 секунд, 168 часов, 7 дней.
Второй состоит из слотов по 5 60-секундных периодов, т.е. 5 минут, в которых среднее значение за этот слот, и всего таких — 8064 штуки, то есть 40320 минут, 672 часа, 28 дней.
Третий — слоты по 60*60-секунд (1 час), весь период 8760 часов, 365 дней. Таким образом, максимальный период хранения данных — 1 год.
Параметр «0.5» говорит о том, что в слоте допускается до половины неизвестных (nan) значений.
То есть, если по какой-то причине части данных не было — игнорируем, и считаем по имеющимся.
Размер этого файла составил чуть больше 200 килобайт, и расти он уже не будет.
Самих записей не так уж много, поэтому выборка по ним будет работать быстро.
Для внесения данных есть команда update:
rrdtools update termo.rrd N:27.54
Эта команда запишет температуру 27.54 на текущее время.
Всё остальное — выбор последнего знанения, усреднения, раскладку по буферам и прочее — система сделает сама.
Можно вместо N указать unixtime — тогда данные будут добавлены для указанного времени — но для мониторинга обычно это не нужно.
В случае «парных» величин (температура-влажность, трафик входящий-исходящий) можно при создании файла базы указывать по нескольку DS с разными именами — храниться они будут в одном файле в одинаковых RRA.
В этом случае при update очередные значенияя также указываются парами — например, «N:25.12:56.4».
Получение данных за период — fetch:
rrdtools fetch termo.rrd AVERAGE -s -3600 -e -3000
Запрошены усредненные данные за период от 3600 секунд назад до 3000 секунд назад. Конец периода можно не указывать — будет до настоящего момента. Можно использовать модификаторы типа h — час, d — день.
Ответ будет примерно таким:
1779970020: 1.1446144343e+01
1779970080: 1.1548646165e+01
1779970140: 1.1466569217e+01
1779970200: 1.1453367132e+01
1779970260: 1.1357315488e+01
1779970320: 1.1213944783e+01
1779970380: 1.1060893320e+01
1779970440: 1.0848092697e+01
Формат: unixtime: value
Например, теммпература в 1779970260 сек — 11.357315488 градуса (усредненная).
Теперь по ним можно строить графики, используя свои любимые инструменты, или запускать какую-то аналитику.
Также можно сразу получить картинку:
rrdtools graph - DEF:x=termo.rrd:t:AVERAGE LINE1:x#f00 -s -7d > out.png
Получаем картинку в PNG, для чего указываем источник данных x = t из файла termo.rrd, и график в виде линии толщиной 1px по переменной x, рисуя его красным цветом (#f00).
Период — за последние 7 дней.

При желании там много чего можно настроить: подключить разные файлы, извлекать разные данные, рисовать разным цветом, добавлять надписи и так далее. В этом случае дополнительные инструменты для рисования картинок уже не нужны.
Все это более подробно расписано в man rrdtools, я просто привел несколько базовых примеров. А вот как это оказалось можно использовать на практике (тоже есть в man, но немного модифицируем):
Допустим, у нас есть какой-то скрипт, собирающий данные с датчиков, на машине A.
Веб-сервер, показывающий дашборды — на машине B.
Плюс еще машины C, D, и вообще какие-нибудь девайсы на ESP, которые тоже могут давать данные.
И работать с файлами — ну, это не очень удобно, не копировать же их туда-сюда, тем более не везде можно установить rrdtools.
Но можно превратить rrdtools в сетевой микросервис:
Если взять старый добрый inetd (а лучше xinetd) — можно “повесить” rrdtools на какой-то порт на одной из машин.
В этом случае файлы rrd будут находиться там, а вот работать с ними, в том числе вносить, получать данные или строить графики, можно хоть с ESP.
Для inetd — нужно определить “имя сервиса” для rrd в /etc/services
rrd 23456/tcp # примерно так
или взять оттуда любое свободное готовое.
Создать юзера rrduser, и выделить место для файлов, например в /var/rrd/
Потом указать в /etc/inetd.conf:
rrd stream tcp nowait rrduser /usr/bin/rrdtool rrdtool - /var/rrd
После запуска inetd на порту 23456 будет доступен rrdtools, которому можно отправлять команды.
Если использовать xinetd — там примерно так же, только можно еще и ограничить, на каком интерфейсе слушать порт:
/etc/xinet.d/rrdservice services{ bind = 192.168.1.11 port = 23456 socket_type = stream protocol = tcp wait = no user = rrduser disable = no server = /usr/bin/rrdtool server_args = rrdtool - /var/rrd}
Ограничивать по юзеру и интерфейсу нужно потому, что у rrdtools среди команд есть такие как list, которая позволяет просматривать каталоги на сервере (если есть права), и create в принципе может создавать rrd в любом доступном каталоге.
Можно вообще засунуть rrdtools в docker — чтобы там ничего лишнего точно не было.
Но в любом случае в итоге — сетевой микросервис.
Можно отправлять команды примерно так:
echo "update termo.rrd N:11.44" |/usr/bin/nc -N server portecho "fetch termo.rrd LAST -s -3600 -e -3200" |/usr/bin/nc -N server port
Если к серверу есть доступ — можно создавать и работать с файлами по сети. Устанавливать на разные машины rrdtools не нужно.
Только помнить о том, что защиты как таковой там нет — вы всегда можете просто случайно или специально перезаписать существующий файл, создав его заново.
Но в ряде случаев это приемлемо.
ссылка на оригинал статьи https://habr.com/ru/articles/1040890/