26.10.2011 15:51
OlegON
 
Рано или поздно ИТ-специалисты приходят к выводу о необходимости хранить историю каких-то параметров и смотреть ее графическое представление. Я при всем желании не запомню, сколько было посетителей на форуме полгода назад, а сколько - год. Аналогичным образом можно радовать работодателя графиком выручки или количеством чеков. Я рисую rrdtool графики загрузки БД в оптимизаторе. Вариантов применений - миллион. Проблема была только в способе преобразования данных в графику. Сначала был опробован mrtg, тоже неплохое средство, но нацеленное на анализ сетевого траффика или просто каких-то двух параметров. Не помню, обертка он к rrdtool или предшественник, но из него я вырос. Чтобы объяснить, что именно я делаю, забегу вперед, вот статистика форума.

Код:
#!/bin/bash
cd /path
GUESTS=`mysql olegon -B -N -e 'select count(*) from cybvilxh_guests'`
USERS=`mysql olegon -B -N -e 'select count(*) from user where lastactivity>unix_timestamp(date_sub(now(),interval 24 hour))'`
let ALL=$USERS+$GUESTS
WRITERS=`mysql olegon -B -N -e 'select count(distinct(userid)) from post where dateline>unix_timestamp(date_sub(now(),interval 24 hour))'`
JOINS=`mysql olegon -B -N -e 'select count(userid) from user where joindate>unix_timestamp(date_sub(now(),interval 24 hour))'`
THREADS=`mysql olegon -B -N -e 'select count(*) from thread where dateline>unix_timestamp(date_sub(now(),interval 24 hour))'`
POSTS=`mysql olegon -B -N -e 'select count(*) from post where dateline>unix_timestamp(date_sub(now(),interval 24 hour))'`
RRDB='forumstat.db'
RRIMG='/stats/forumstat.png'
RRIMM='/stats/forumstat2.png'
#rm $RRDB
if [ ! -f $RRDB ]
then
step=86400
timestamp=$(( $(date +%s) / $step * $step ))
/usr/bin/rrdtool create $RRDB --start $(( $timestamp - $step ))-1d --step $step \
DS:all:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:users:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:guests:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:writers:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:joins:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:threads:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
DS:posts:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732
fi
/usr/bin/rrdtool update $RRDB -- -86400:$ALL:$USERS:$GUESTS:$WRITERS:$JOINS:$THREADS:$POSTS
#/usr/bin/rrdtool update $RRDB N:$ALL:$USERS:$GUESTS:$WRITERS:$JOINS:$THREADS:$POSTS
/usr/bin/rrdtool graph $RRIMG -E -N --lazy -w 1200 -h 450 --start -2y \
DEF:all=$RRDB:all:LAST \
DEF:users=$RRDB:users:LAST \
DEF:guests=$RRDB:guests:LAST \
DEF:writers=$RRDB:writers:LAST \
AREA:all#00FFFF:All \
AREA:users#0000FF:Registered \
AREA:guests#FF0033:Guests \
AREA:writers#333333:Writers
/usr/bin/rrdtool graph $RRIMM -E -N --lazy -w 1200 -h 450 --start -2y \
DEF:threads=$RRDB:threads:LAST \
DEF:posts=$RRDB:posts:LAST \
DEF:joins=$RRDB:joins:LAST \
DEF:writers=$RRDB:writers:LAST \
AREA:threads#00FFFF:Threads \
AREA:posts#0000FF:Posts \
AREA:joins#FF0033:Joins \
AREA:writers#333333:Writers
Вот код. Ниже я его прокомментирую. Обращаю внимание, что вверху скрипта самые настоящие запросы на получение статистики из Vbulletin.
26.10.2011 16:24
OlegON
 
В первой части скрипта я собираю статистические данные в переменные. Так с ними удобнее работать, дебажить и т.п. От дебага остался и rm, которым я пересоздавал БД rrdtool. Далее, если файл БД не существует, то он создается. Удобно держать скрипт готовым к неожиданностям. Я его частично срисовал с оптимизаторского, поэтому в нем учитывается отсутствие БД. Создается БД командой rrdtool create, в результате которой появляется единственный файлик, довольно скромных размеров. Строка с timestamp появилась в результате обхода несколько непонятной фичи, связанной с учетом суток (86400 секунд), если не начать БД правильно, в нее не попадают значения при таком интервале, убил на это уйму времени, никак не мог понять, почему. Step, т.е. шаг в моей БД равен 86400 секундам, т.е. раз в сутки я буду класть в нее данные по загрузке предыдущих 24 часов.
Разберем типовой шаблон:
Цитата:
DS:all:GAUGE:172800:U:U \
RRA:LAST:0.5:1:732 \
первая строчка описывает источник с именем all. Этот источник не накопительный, поэтому GAUGE, а не COUNTER. К первому типу относят, например, температуру, ко второму - количество посетителей форума с момента его создания. Поскольку я анализирую посетителей за 24 часа, то сегодня их может быть 2000, завтра 1000, т.е. значения колеблются в обе стороны. Цифра 172800 обозначает период за который данных может не быть, прежде чем в графике появится дырка. В моем случае это 2 суток. Две буквы U обозначают, что мне неизвестны минимальные и максимальные значения данных. В противном случае их бы лучше было указать. Далее идет строчка описания архива. Из нее следует простой вывод, что хранится 1 значение, будет использовано LAST - последнее и всего будет 732 ячейки (помня про интервал в сутки, получим приблизительно два года). Вот и повторяем этот шаблон для разных запоминаемых параметров...
26.10.2011 16:31
OlegON
 
Цитата:
/usr/bin/rrdtool update $RRDB -- -86400:$ALL:$USERS:$GUESTS:$WRITERS:$JOINS:$THREADS:$POSTS
rrdtool update это команда на апдейт базы. Проще простого. Цифра -86400 обозначает, что данные я привязываю к предыдущему дню, для текущего надо писать N. Далее, через ":" идут значения параметров, которые я задал выше, при создании БД. Данные будут лезть в БД, пока хватает места по заданным ячейкам (732 в моем случае) после чего новые будут запихиваться, выдавливая самые старые. Данные привязываются ко времени, поэтому, раз определили, что их 1 значение для 86400, то хоть обобновляйся, новые данные в БД не попадут.
26.10.2011 16:56
OlegON
 
Далее идут две команды rrdtool graph (картинки две). В них все тоже предельно просто. Размерность, сглаживание, не перезаписывать, если картинка актуальная, картинка за 2 года. Ниже идут описания графиков... Из них можно отметить, что вместо AREA - заштрихованного графика, можно использовать LINE1, простую линию...
04.11.2011 13:55
OlegON
 
Сделал картинки поменьше и с меньшей историей. Наткнулся на необходимость менять подписи по Х. Оказалось очень просто.
Цитата:
--x-grid HOUR:24:DAY:7:MONTH:1:0:%b
серая черта раз в 24 часа, красная, раз в неделю, подпись раз в месяц
16.09.2012 08:44
OlegON
 
Убился, не получается даже найти информацию.
Каким образом можно вывести на график сумму значений за неделю? Т.е. в базу, как выше писал, запихиваю каждый день данные. Каким образом можно при выводе графика собрать несколько точек и показать сумму одной точкой?
16.09.2012 12:11
OlegON
 
Надоело. Поставил среднее.
Код:
DEF:threads=$RRDB:threads:LAST:step=604800:reduce=AVERAGE \
буду благодарен, если кто-то сумму найдет.
22.11.2016 12:24
OlegON
 
Понадобилось сделать отображение темпов роста записей. Несколько штук в час.
Шаблон создания базы традиционный
Код:
step=3600
timestamp=$(( $(date +%s) / $step * $step ))
/usr/bin/rrdtool create $RRDB --start $(( $timestamp - $step ))-1w --step $step \
DS:gcount:GAUGE:7200:U:U \
RRA:LAST:0.5:1:10080
Однако, если брать COUNTER, то rrdtool пытается вычислять средние значения посекундно, получаются очень маленькие значения, видимо, а при построении графиков вылезают миллионы. В общем, COUNTER достаточно бесполезен на медленно растущих значениях при большом итоге. Оставил GAUGE. А вот построение графика немного изменил.
Код:
DEF:gcount=$RRDB:gcount:LAST \
CDEF:cnt=gcount,PREV\(gcount\),- \
TEXTALIGN:left \
LINE1:cnt#00FF00 \
GPRINT:gcount:LAST:"Всего\:%1.0lf"
как видно, можно использовать не только DEF, но и CDEF, в котором, в свою очередь, можно получить предыдущее значение ячейки и вычесть его из текущего значения "PREV\(gcount\)" (скобки экранируются). Очень даже удобно и красиво. Главное - не зацикливаться на том, что необходимо забить нужные значения в базу. Можно с ними оперировать при построении графика.
18.08.2019 10:18
OlegON
 
Еще немаловажный нюанс, до которого руки дошли только сейчас. Дело в том, что rrdtool создает свои базы исключительно в UTC. Как я понял, это вбито железно и поменять нельзя. Более того, графики тоже в UTC по умолчанию рисуются. Но с графиками проще, можно задать TZ
Код:
export TZ="Europe/Moscow"
а вот с данными все плохо. Если вы рисуете графики ежедневные или со средними значениями за сутки, то часть данных может съехать в другие сутки, поскольку они (сутки) разделяются по UTC. Т.е. если я записываю данные в полночь, они в реальности идут за предыдущее число, поскольку в полночь по Москве, в UTC еще предыдущие сутки, 21:00. Если кто-то знает другой способ сделать правильно - скажите, пожалуйста, а я пока ничего не придумал, кроме как докидывать еще три часа (свой часовой пояс от UTC), записывая данные, т.е. вместо N вписываю
Код:
$(( $(date +%s) + 10800 ))
13.05.2021 19:08
OlegON
 
Еще на что надо обратить внимание, что если запихиваете данные, то они должны с точностью до 300 секунд укладываться в сетку, которую вы нарисовали при создании базы.
Соответственно, если у вас шаг 86400 (сутки), то укладывать в базу надо именно в 00:00UTC, либо задавать время самому.
Я, соответственно, округляю текущие сутки так (в ячейку за вчерашний день)
Код:
timestamp=$(($(date +%s)/86400*86400-86400))
rrdtool update $RRDB $timestamp:$GCOUNT:$BCOUNT
Часовой пояс GMT +3, время: 08:27.

Форум на базе vBulletin®
Copyright © Jelsoft Enterprises Ltd.
В случае заимствования информации гипертекстовая индексируемая ссылка на Форум обязательна.