Translate

понеділок, 11 квітня 2016 р.

Graphite Configuration. Sending Metrics Using CollectD, StatsD

Збір статистики всіх систем - дуже важлива річ, адже дозволяє оперативно реагувати на будь-які відхилення в їх роботі, приймати рішення щодо збільшення потужностей чи оптимізацій. А представлення такої статистики у виді графіків зробить процес моніторингу більш наочним та зручним.

Раніше я вже писав про побудову графіків за допомогою Cacti, графічний бекенд до Nagios Nagiosgraph, в основі побудови графіків яких лежить RRDtool. Дуже можливо, що це саме те, що вам необхідно. Проте цього разу мова піде про Graphite, що має подібну до RRDtool логіку збереження даних для зображень графіків.

Graphite складається з таких компонентів:

  • Carbon - storage-бекенд, написаний на Twisted Framework. Приймає дані, по-замовчуванню на 2003 порту, та в певні проміжки часу записує їх на диск, використовуючи Whisper. Задля масштабування стандартний процес carbon-cache.py, котрого більш ніж досить у звичайних конфігураціях, може бути доповнений додатковими процесами carbon-relay.py та carbon-aggregator.py. Перший може виступати як балансувальника між декількома carbon-cache.py процесами, а другий - у якості проміжного буферу.
  • Whisper - storage-engine, бібліотека бази Graphite, використовується для збереження даних. Відповідає за реорганізацію даних, що отримав Carbon: переважно перетворює більш точні серії даних в менш точні та довгострокові задля більшої ефективності використання дискового простору. У залежності від наявних серій, може показувати більш точні дані на коротких діапазонах часу, або менш точні на більш довгих. Політика точності, тип агрегації та тривалості збереження серій даних звісно може налаштовуватись. В перспективі Whisper планується замінити на Ceres. Суть в тому, що Whisper на початку створює файли серій метрик фіксованого розміру і з плином часу, в разі зменшення точності вимірів (rollup/downsampling/retention/storage aggregation/compaction) розмір цих файлів не зменшується. Окрім того Whisper, для запису нових метрик, створює на диску файли наперед визначеного розміру,  що веде до неефективного використання дискового простору. Ceres вже не володіє останнім недоліком та краще працює з розподіленими сховищами і, як наслідок, один файл метрик може лежати на декількох серверах. Але, на противагу, він менш стабільний. Є звісно і інші альтернативи для storage-engine.
  • Веб-панель Graphite/API-сервер - панель/API для перегляду графіків, отриманих із серій даних Whisper. Також має можливість побудови панелей для швидкого перегляду груп графіків. Написана на Django з використанням бібліотеки Cairo.

Підсумуємо. Carbon отримує дані, та записує метрики кожний сталий проміжок часу, Whisper агрегує їх залежно від політики збереження, а веб-панель Graphite надає можливість їх переглядати.
Закінчимо на теоретичному мінімумі та перейдемо до практики. Так буде легше все зрозуміти. Налаштування буде описано для Ubuntu 14.04. Домен майбутнього Graphite - graphite.me, IP - 192.168.1.30.

Пакети Graphite доступні через стандартні репозиторії Ubuntu:

# aptitude update
# aptitude install graphite-web graphite-carbon

Після виконання команд, установщик запитає чи не потрібно очистити директорію /var/lib/graphite/whisper. І це насправді не важливо, адже ми попередньо не збирали жодної статистики.

Веб-панель Graphite потребує базу для збереження власних даних конфігурації. Для цього встановимо PostgeSQL та налаштуємо окремого користувача:

# aptitude install postgresql libpq-dev python-psycopg2
# sudo -u postgres psql

> CREATE USER graphite WITH PASSWORD 'p@ssw0rd';
> CREATE DATABASE graphite WITH OWNER graphite;
> \q

За необхідності назви користувача і бази можна змінити на інші, а пароль обов’язково необхідно встановити більш складний.

По-замовчуванню веб-панель  використовує SQLite і, залежно від потреб, її може бути більше ніж досить. Ми опціонально скористались PostgeSQL, проте Django підтримує і інші варіанти.

Редагуємо конфігураційний файл веб-панелі:

# vim /etc/graphite/local_settings.py
...
SECRET_KEY = 'a_salty_string'
...
TIME_ZONE = 'UTC'
...
USE_REMOTE_USER_AUTHENTICATION = True
...
DATABASES = {
    'default': {
        'NAME': 'graphite',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'graphite',
        'PASSWORD': 'p@ssw0rd',
        'HOST': '127.0.0.1',
        'PORT': ''
    }
}
...

Секретний ключ бажано згенерувати достатньо довгим, він буде виступати в якості додаткового аргументу (salt) при хешуванні. Дуже раджу взяти за правило ставити у якості часового поясу Грінвіч: і віднімати, і додавати години зручно, і немає переводу години назад-вперед. Опція USE_REMOTE_USER_AUTHENTICATION відповідає за можливість створення додаткових аккаунтів в панелі Graphite. Ну і нарешті вказуємо параметри, до щойно створеної бази: ім’я бази, python-драйвер для роботи з PosgreSQL базою, користувач, від імені якого будуть відбуватись записи до бази, пароль коористувача, хост, порт (у цьому випадку буде обраний дефолтний порт для PostgreSQL).

Створюємо структуру бази для Graphite:

# graphite-manage syncdb

В процесі виконання команди буде запропоновано створити користувача для аутентифікації в панель Graphite.

Редагуємо налаштування Carbon. Для початку дозволимо його завантаження:

# vim /etc/default/graphite-carbon
...
CARBON_CACHE_ENABLED=true
...

Дозволимо ротацію логів Carbon:

# vim /etc/carbon/carbon.conf
...
ENABLE_LOGROTATION = True
...

Відкриємо storage-схему Carbon:

# vim /etc/carbon/storage-schemas.conf

[carbon]
pattern = ^carbon\.
retentions = 60:90d

[default_1min_for_1day]
pattern = .*
retentions = 60s:1d

Допоки схема має дві секції: для самого Carbon (по-замовчуванню він логує свої метрики) та секція для всіх інших метрик. Далі йде патерн за ім’ям якого і визначається чи відносяться метрики до секції та політика збереження метрик (retentions). Останній параметр складається з серії цифр, що розділені двокрапкою. Перше значення до двокрапки вказує якою має бути точність серії даних і на протязі якого часу вона має зберігатись.

Розберемось конкретніше на прикладі нижче:

[test]
pattern = ^test\.
retentions = 10s:10m,1m:1h,10m:1d

Секція test (директорія в веб-панелі Graphite матиме таку ж назву) описує
політику збереження та агрегації метрик, що прийдуть з іменем "test." на самому початку. Параметр retentions складається з 3-ох груп цифр - точність та проміжок часу для якого має зберігатись задана точність.

10s:10m - метрики за кожні 10 секунд (по замовчуванню це максимальна точність Carbon) будуть зберігатись лише останні 10 хвилин і надалі вони будуть агрегуватись в меншу точність (наступна група цифр).

1m:1h - в залежності від алгоритму агрегації, дані метрик з більш точних серій будуть агрегуватись в менш точні. У цьому випадку 6 метрик за хвилину будуть агреговані в одну і така точність буде зберігатись на протязі години. По-замовчуванню використовується average тип агрегації, детальніше про це - нижче.

10m:1d - 10 метрик із попередньої серії будуть агреговані в одну і зберігатимуться на протязі останнього дня. Все інше буде затиратись і таким чином лишатимуться лише найсвіжіші дані.

У залежності від величини запитаного часового проміжку в веб-панелі Graphite і буде показана максимально доступна точність.

Отже, додамо вищезгадану секцію [test] до конфігураційного файлу storage-schemas.conf перед секцією [default_1min_for_1day], адже вони читаються послідовно згори донизу.

По-замовчуванню використовується average тип агрегації для створення менш детальних архівів. Проте є і інші варіанти, ось їх перелік:

  • average - середнє значення з усіх наявних серій 
  • sum - сума всіх значень на протязі певного часу
  • min - мінімальне значення
  • max - максимальне
  • last - останнє. Тобто останнє значення і буде виступати значенням для агрегації

Їхнє існування виправдане тим, що average не завжди задовольняє всі потреби. Наприклад при зборі метрики кількості помилок, зручно мати суму всіх значень за певний проміжок часу і в цьому випадку може допомогти типа агрегації sum.

Типом агрегації можна оперувати в storage-aggregation.conf.

# cp /usr/share/doc/graphite-carbon/examples/storage-aggregation.conf.example /etc/carbon/storage-aggregation.conf

# cat /etc/carbon/storage-aggregation.conf
...
[min]
pattern = \.min$
xFilesFactor = 0.1
aggregationMethod = min
...

Відповідно правилам, щоб був активований той чи інший тип агрегації необхідно щоб метрики приходили з певним значенням у назві. Наприклад, щоб було агреговано по методу min необхідно, щоб в кінці метрики, що надсилається, було вказано значення .min (pattern = \.min$)

xFilesFactor - мінімальний відсоток доступних значень, котрий необхідний агрегації. Наприклад, якщо прийде менше 10% метрик, наприклад, у результаті мережевих проблем, Graphite не буде агрегувати ці дані.

Стартуємо carbon-процес:

# service carbon-cache start

Graphite тепер вже працює і збирає метрики. Проте хорошою практикою є установка веб-серверу попереду, адже дозволить більш оптимально обробляти запити та надасть додаткові можливості налаштування. Веб-сервер можна обрати будь-який, котрий вміє проксувати запити на інші сервери програм. Наприклад, Apache.

# aptitude install apache2 libapache2-mod-wsgi
# a2dissite 000-default
# cp /usr/share/graphite-web/apache2-graphite.conf /etc/apache2/sites-available
# a2ensite apache2-graphite
# service apache2 reload

Відкриваємо лінку в браузері http://graphite.me:


Автентифікуємось по вказаним раніше логіну/паролю (вгорі зліва є кнопка Login):


І, зачекавши трохи часу, можна спостерігати відображення метрик:


Це лише сервісні дані роботи Carbon, вони не надто цікаві.

Відправити власні дані в Graphite зовсім не важко. Для цього необхідно указати повне ім'я метрики, її значення та час, коли ця метрика була активною:

# echo "test.count 4 `date +%s`" | nc -q0 127.0.0.1 2003

З інтервалом в 10 секунд (адже з такою періодичністю логує дані Carbon) виконаємо ще 2 команди:

# echo "test.count 14 `date +%s`" | nc -q0 127.0.0.1 2003
# echo "test.count 2 `date +%s`"  | nc -q0 127.0.0.1 2003

Завдяки nc метрики будуть відправлені по UDP протоколу.

І результат не примусить себе довго чекати:


Засобами bash можна зганерувати базове тестове навантаження:

$ TIMER='30m'
$ timeout -sHUP ${TIMER} bash -c 'while [ 0 ]; do echo "dev.count "${RANDOM}" `date +%s`" | nc -q0 127.0.0.1 2003; done'

Крапка в назві метрики вказує на відповідну піддиректорію, де фізично лежатиме графік. В нашому випадку це /var/lib/graphite/whisper/test та назва файлу метрик - count.wsp:

# file /var/lib/graphite/whisper/test/count.wsp 
/var/lib/graphite/whisper/test/count.wsp: data

З часом, Whisper створить додаткові бази для кожного з проміжку агрегації.
Відправка даних для Graphite може відбуватись не лише за допомогою plaintext сповіщень на порт Carbon. Graphite також працює з Advanced Message Queueing Protocol (AMQP), pickle, різними бібліотеками на зразок Coda Hale.

Щоб внести різноманітність встановимо Collectd, що вміє слідкувати за системою та відсилати метрики в Graphite. Установка не складна:

# aptitude update
# aptitude install collectd collectd-utils

Його я установив на окремий сервер gclient.me (192.168.1.31), проте в навчальних цілях нічого не заважає проінсталювати його на хост із Grapgite.

Налаштовуємо перевірки, за якими будемо спостерігати:

# vim /etc/collectd/collectd.conf
...
Hostname "gclient_me"
...
LoadPlugin apache
LoadPlugin cpu
LoadPlugin df
LoadPlugin entropy
LoadPlugin interface
LoadPlugin load
LoadPlugin memory
LoadPlugin processes
LoadPlugin rrdtool
LoadPlugin users
LoadPlugin write_graphite
...

У випадку, якщо доменне ім'я було вірно сконфігуроване для сервера, то замість хостнейма можна активувати опцію FQDNLookup.
Деякі з перевірок потребують додаткових налаштувань, тому в цьому ж файлі розкоментуємо/додамо наступне:

<Plugin apache>
    <Instance "Graphite">
        # укажіть власний домен
        URL "http://gclient.me/server-status?auto"
        Server "apache"
    </Instance>
</Plugin>
...
<Plugin df>
    # диск за яким необхідно спостерігати
    Device "/dev/sda1"
    MountPoint "/"
    FSType "ext3"
</Plugin>
...
<Plugin interface>
    # ім'я інтерфейсу
    Interface "eth0"
    IgnoreSelected false
</Plugin>
...

Та остання секція - куди відсилати Graphite-метрики:

...
<Plugin write_graphite>
    <Node "graphing">
        Host "graphite.me"
        Port "2003"
        Protocol "tcp"
        LogSendErrors true
        Prefix "collectd."
        StoreRates true
        AlwaysAppendDS false
        EscapeCharacter "_"
    </Node>
</Plugin>
...

Вище ми вказали, що необхідно збирати статистику активності Apache2, для чого, як не дивно, необхідно установити Apache та дозволити її зі сторони самого веб-сервера:

# aptitude install apache2 libapache2-mod-wsgi

# vim /etc/apache2/sites-enabled/000-default.conf

<VirtualHost *:80>
...
        <Location "/server-status">
           SetHandler server-status
           Require all granted
        </Location>

</VirtualHost>

# service apache2 reload

Для перевірки коректності налаштувань варто поглянути чи працює статистика на http://gclient.me/server-status


Додамо storage-схему для collectd. Для чого перейдемо на graphite.me та відредагуємо storage-schemas.conf:

# vim /etc/carbon/storage-schemas.conf
...
[collectd]
pattern = ^collectd.*
retentions = 10s:1d,1m:7d,10m:1y
...

Це все має бути записано до default секції! Перезапускаємо carbon на gclient.me:

# service carbon-cache stop
# service carbon-cache start

Та перезапускаємо collectd на graphite.me:

# service collectd stop
# service collectd start

За хвилину з'явиться нова директорія collectd з графіками:



Натиснувши кнопку Dashboard вгорі праворуч, можна перейти в інтерфейс створення дошок графіків:


Graphite дуже популярний проект з багатьма доповненнями та альтернативними компонентами, серед них - StatsD. Ми розберемось як встановлюється і працює оригінальна імплементація StatsD на nodejs від Etsy, проте реалізація StatsD є також і на купі інших мов.

Якщо не вдаватись в подробиці, StatsD - це проміжний сервіс між Carbon та програмою, якій необхідно відсилати метрики. Існує багато бібліотек, котрі легко можуть бути підключені до вже існуючої програми для відправки даних в Statd. Statd працює на UDP порту, що підвищує продуктивність його роботи, проте за рахунок надійності доставки метрик. StatD може агрегувати дані в собі і видавати вже готове значення раз в 10 секунд для Carbon. Тобто StatD бере до уваги всі метрики, що надходять до нього.

Закінчимо зі вступом та перейдемо до установки StatsD. Установлюється він нетривіальним способом, адже готових пакетів немає:

# aptitude install git nodejs-legacy devscripts debhelper dh-systemd
# mkdir ~/build
# cd ~/build
# git clone https://github.com/etsy/statsd.git
# cd statsd
# dpkg-buildpackage
# cd ..
# dpkg -i statsd*.deb

У мене після цього з'явились проблеми з nodejs залежностями, які можна виправити наступним чином:

# aptitude install -f

StatsD після установки стартує автоматично. Зупинимо його, адже треба провести додаткові налаштування. Установку StatsD я провів на окремому від Graphite сервері gclient.me, що необхідно відобразити в конфігураційних файлах StatsD:

# vim /etc/statsd/localConfig.js

{
  graphitePort: 2003
, graphiteHost: "graphite.me"
, port: 8125
, graphite: {
    legacyNamespace: false
  }
}

Опишемо окрему storage-схему для StatsD на сервері Graphite, яку звісно традиційно необхідно додати до default-схеми:

# vim /etc/carbon/storage-schemas.conf
...
[statsd]
pattern = ^stats.*
retentions = 10s:1d,1m:7d,10m:1y
...

StatsD розширює можливості агрегації Graphite. Для того щоб вони вірно інтерпретувались, необхідно відкоригувати storage-aggregation.conf:

# vim /etc/carbon/storage-aggregation.conf

[min]
pattern = \.min$
xFilesFactor = 0.1
aggregationMethod = min

[max]
pattern = \.max$
xFilesFactor = 0.1
aggregationMethod = max

[count]
pattern = \.count$
xFilesFactor = 0
aggregationMethod = sum

[lower]
pattern = \.lower(_\d+)?$
xFilesFactor = 0.1
aggregationMethod = min

[upper]
pattern = \.upper(_\d+)?$
xFilesFactor = 0.1
aggregationMethod = max

[sum]
pattern = \.sum$
xFilesFactor = 0
aggregationMethod = sum

[gauges]
pattern = ^.*\.gauges\..*
xFilesFactor = 0
aggregationMethod = last

[default_average]
pattern = .*
xFilesFactor = 0.5
aggregationMethod = average

Це фінальний вигляд конфігураційного файлу. Після цього перезапускаємо carbon-cache на graphite.me:

# service carbon-cache

Та стартуємо statsd на gclient.me:

# service statsd start

З'явилась нова директорія метрик stats:


Дані до StatsD відсилаються в дещо інший спосіб ніж до Graphite. Для StatsD також необхідно вказувати тип метрик, тобто як саме їх необхідно агрегувати:

# echo "metric_name:metric_value|metric_type" | nc -u -w0 gclient.me 8125

metric_type в StatsD може бути таким:

  • c: count. Дані, що приходять за інтервал часу сумуються і надсилаються до Carbon. Одразу продемонструю це на прикладі. Виконаємо команди, подані нижче, на протязі 10 секунд:

    # echo "sample.count:1|c" | nc -u -w0 gclient.me 8125
    # echo "sample.count:1|c" | nc -u -w0 gclient.me 8125
    # echo "sample.count:1|c" | nc -u -w0 gclient.me 8125
    # echo "sample.count:1|c" | nc -u -w0 gclient.me 8125
    # echo "sample.count:1|c" | nc -u -w0 gclient.me 8125



    З Graphite видно, що було створено 2 графіка, на котрих видно сумарне значення на протязі 10 секунд та середнє значення в секунду - rate. Якщо на протязі наступного інтервалу дані приходити не будуть - графік метрик піде в нуль.
  • g: gauge. Відображається лише останнє значення на протязі проміжку часу і надалі воно зберігається допоки не буде отримане інше значення. Схоже на принцип роботи датчика пального чи чогось такого.

  • # echo "sample.gauge:14|g" | nc -u -w0 gclient.me 8125


    Через декілька хвилин виконаємо наступну команду:

    # echo "sample.gauge:10|g" | nc -u -w0 gclient.me 8125

    А потім ще одну, проте також вичекаємо деякий інтервал:

    # echo "sample.gauge:18|g" | nc -u -w0 gclient.me 8125


    Тож значення змінюється лише коли надсилається значення відмінне від попереднього і не скидається в нуль за його відсутності.
  • s: sets. Запам'ятовує і відображає кількість лише унікальних значень. Виконаємо групу команд:

  • # echo "sample.set:50|s" | nc -u -w0 gclient.me 8125
    # echo "sample.set:50|s" | nc -u -w0 gclient.me 8125
    # echo "sample.set:50|s" | nc -u -w0 gclient.me 8125
    # echo "sample.set:50|s" | nc -u -w0 gclient.me 8125
    # echo "sample.set:11|s" | nc -u -w0 gclient.me 8125

    Зображення в Graphite буде наступним:
    Тож спершу було відправлено три значень "50", де лише одне унікальне, а потім, на протязі наступного проміжку - вже два унікальних: "50" і "11".
  • ms: timers. При відправленні метрик з даним типом, StatsD одразу розраховує декілька інших метрик за певний проміжок часу, таких як середній час приходу метрик, найвище та найменше значення і т.п.

    Спробуємо це на практиці, виконавши наступне:

    # echo "sample.timer:512|ms" | nc -u -w0 gclient.me 8125
    # echo "sample.timer:400|ms" | nc -u -w0 gclient.me 8125
    # echo "sample.timer:700|ms" | nc -u -w0 gclient.me 8125
    # echo "sample.timer:10|ms"  | nc -u -w0 gclient.me 8125



    Подібний тип агрегації може бути корисний для розуміння як працює програма, які затримки вона продукує і т.п.
Із повним списком можливих агрегацій, що підтримує оригінальна реалізація StatsD від Etsy можна ознайомитись за посиланням https://github.com/etsy/statsd/blob/master/docs/metric_types.md. Ця реалізація наразі вже досить довго не підтримується, тому краще звернути увагу на більш актуальні реалізації https://github.com/etsy/statsd/wiki#server-implementations

Ну і нарешті спробуємо ці дані відсилати з програми, наприклад, написаної на мові Python. Установимо необхідні пакети та бібліотеки для інтеграції StatsD з Python:

# apt-get install python-pip
# pip install python-statsd

# python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import statsd
>>> gauge = statsd.Gauge('Python_metric')
>>> gauge.send('some_value', 15)
True
>>> gauge.send('some_value', 9)
True
>>> gauge.send('some_value', 25)
True

Переглянемо в Graphite панелі, що нового з'явилось:


Дещо більше прикладів використання бібліотеки python-statsd можна знайти за посиланням https://pypi.python.org/pypi/python-statsd

Відверто кажучи, Graphite володіє не найзручнішою та функціональною веб-панеллю, проте існує чудова заміна для неї, що має назву Grafana. Після неї, здається, немає жодного сенсу шукати щось краще. У наступній статті і піде мова про установку та налаштування Grafana до вже працюючого інстансу Graphite.

Посилання:
http://graphite.readthedocs.org/en/latest/index.html
https://www.digitalocean.com/community/tutorials/an-introduction-to-tracking-statistics-with-graphite-statsd-and-collectd
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-graphite-on-an-ubuntu-14-04-server
https://www.digitalocean.com/community/tutorials/how-to-configure-collectd-to-gather-system-metrics-for-graphite-on-ubuntu-14-04
https://www.digitalocean.com/community/tutorials/how-to-configure-statsd-to-collect-arbitrary-stats-for-graphite-on-ubuntu-14-04
https://github.com/graphite-project/carbon
http://www.franklinangulo.com/blog/?offset=1400511195558&category=graphite
http://help.ubuntu.ru/wiki/graphite
https://habrahabr.ru/company/tcsbank/blog/252907/
http://www.canopsis.org/collectd-graphite

Немає коментарів:

Дописати коментар