Введення в Riemann: моніторинг і аналіз подій

Riemann

У попередніх статтях ми не раз зачіпали проблематику моніторингу, збору та
зберігання метрик (див., наприклад, тут тут). Сьогодні ми хотіли б знову повернутися до цієї теми і розповісти про незвичайному, але вельми цікавому інструменті   Riemann.


&Nbsp;порівняно з іншими системами моніторингу він відрізняється підвищеною складністю,
і      набагато більшою гнучкістю і відмовостійкість. На просторах Інтернету нам доводилося зустрічати публікації, де Riemann характеризують як «найбільш гнучку систему моніторингу в світі». Riemann добре підходить для збору інформації про роботу складних високонавантажених систем у реальному масштабі часу.

Власне кажучи, системою моніторингу в строгому сенсі Riemann не є. Правильніше було б його називати інструментом обробки подій (event processor).
Він збирає інформацію про події хостів і додатків, об'єднує події в потік і передає їх іншим додаткам для подальшої обробки або зберігання. Також Riemann відстежує стан подій, що дозволяє створювати перевірки і розсилати повідомлення.

Riemann розповсюджується безкоштовно по ліцензії Eclipse. Велика частина коду написана Кайлом Кінгсбері, відомому також під псевдонімом Aphyr (до речі, рекомендуємо почитати його блог: там часто бувають цікаві матеріали).

Обробка подій в реальному масштабі часу

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

Ідея обробки подій в режимі, наближеному до реального часу не нова: перші спроби її здійснення робилися ще в наприкінці 1980-х років. &Nbsp;як приклад можна назвати так звані Active Database Systems (активні системи баз даних), які виконували певний набір інструкцій, якщо надходять в базу дані відповідали заданим набором умов.

У 1990-х роках з'явилися системи управління потоками даних (Data Stream Management Systems), які вже могли обробляти дані, що надходять у реальному масштабі часу, і системи обробки складних подій Complex Event Processing, скорочено CEP). Такі системи могли як виявляти події на зовнішніх даних і закладеної внутрішньої логіки, так і здійснювати певні аналітичні операції (наприклад, підраховувати кількість подій за певні період часу).

Прикладами сучасних інструментів обробки складних подій можуть служити, у зокрема, Storm (див. також статтю про на ньому російською мовою) і Esper. Вони орієнтовані на обробку даних без зберігання. Riemann   продукт такого ж класу. У відміну від  ж Storm він набагато більш простий і логічний: вся логіка обробки подій може бути описана лише в одному конфігураційному файлі.
Багатьох системних адміністраторів-практиків ця особливість може і відлякати: конфігураційний файл суті являє собою код на мовою Clojure, але якому написаний і Riemann.

Clojure відноситься до функціональним (а ще точніше кажучи   лиспообразным) мов програмування, що саме по собі вже насторожує. Однак у цьому немає нічого страшного: при всьому своєму своєрідності Clojure не так складний, як здається на перший погляд. Розглянемо його особливості більш детально.

Трохи про Clojure

Clojure являє собою функціональний мовами, створений на базі LISP. Програми, написані на Clojure, працюють на платфоре JVM. Перша версія цієї мови з'явилася в 2007 році. Зовсім недавно вийшла у світло остання на сьогоднішній день версія   1.8.0.

Clojure використовується у проекти таких компаній, як Facebook, Spotify, SoundCloud, Amazon і інших (повний список на офіційному сайті).

У відміну від інших реалізацій LISP для JVM (наприклад, ABCL або Kawa), Clojure не повністю сумісний ні з Common Lisp, ні з Scheme, однак з цих мов у ньому дуже багато запозичено. Є в Clojure і деякі удосконалення, яких немає в інших сучасних діалектах LISP: незмінність даних, конкуретное виконання коду і тощо

Так як Clojure був спочатку спроектований для роботи з JVM, в ньому можна працювати з численними бібліотеками, існуючими для цієї платформи. Взаємодія з Java реалізовано у обидві сторони. можна викликати код, написаний для Java. Можлива також реалізація класів, доступних для виклику з Java і інших мов програмування, які працюють на базі JVM   наприклад, для Scala. Більш детально про Clojure і його можливості можна прочитати в цієї статті, а  на офіційному сайті Riemann. Рекомендуємо також ознайомитися ще з одним коротким, але дуже інформативним введенням в Clojure.

Установка і перший запуск

Щоб працювати у Riemann, спочатку нам знадобиться встановити всі необхідні
залежності: Java і Ruby (на ньому написані деякі додаткові компоненти, які мова ще піде нижче):

$ sudo apt-get -y install default-jre ruby-dev build-essential


Далі завантажимо і встановимо останню версію Riemann:

$ wget https://aphyr.com/riemann/riemann-0.2.10_all.deb
$ dpkg -i riemann-0.2.10_all.deb


Далі виконаємо:

$ sudo service riemann start


Для повноцінної роботи нам знадобитися також встановити написані на Ruby компоненти для збору і метрик:

$ gem install riemann-client riemann-tools 


Ось і всі. Для початку роботи з Riemann все готово. Перш ніж перейти до практичної частини, зробимо невеликий теоретичний відступ і з'ясуємо зміст найважливіших понять: події, потоки і індекс.

Події, потоки і індекс

Базовим поняттям в Riemann є подія. Події можна обробляти, підраховувати, збирати і експортувати в інші програми. Подія може виглядати, наприклад, так:

{:host riemann, :service riemann streams rate, :state ok :description nil, :metric 0.0, :tags [riemann], :time 355740372471/250, :ttl 20}


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

  • :host   ім'я хоста;
  • :service   ім'я спостережуваного сервісу;
  • :state   стан події (ok, warning, critical);
  • :tags   мітки події;
  • :time   час настання події форматі Unix Timestamp;
  • :description   опис події довільній формі;
  • :metric   метрика, асоційована з подією;
  • :ttl   час актуальності події (в секундах).


Деякі події можуть також мати кастомні поля, які можна додавати ак у час створення, так і у час обробки подій (наприклад, поля з додатковими метриками).
Всі події об'єднуються в потоки. Потік — це функція, якою може бути передано подія.

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

:host www, :service apache connections, :state nil, :description nil, :metric 100.0, :tags [www], :time 466741572492, :ttl 20


Це подія, що сталася на хості www в сервісі apache connections. В індексі завжди зберігається остання на поточний момент подія. До індексів можна звертатися з потоків і навіть із зовнішніх сервісів.

Ми вже бачили, що кожна подія містить поле TTL (time to live). TTL — це проміжок часу, протягом якого подія є актуальним. У щойно наведеному прикладі TTL події становить 20 секунд. В індекс потрапляють всі події з параметрами: вузол www :service apache connections. Якщо протягом 20 секунд таких подій не відбувається, буде створено нове подія зі значенням expired в полі state. Потім воно буде додано в потік.

Налаштування

Перейдемо від теорії до практики і займемося конфігуруванням Riemann. Відкриємо файл /etc/riemann/riemann.config. Він являє собою програму на Clojure і за замовчуванням виглядає так:

; -*- mode: clojure; -*-
; vim: filetype=clojure

(logging/init {:file "/var/log/riemann/riemann.log"})

; Listen on the local interface over TCP (5555), UDP (5555), and websockets
; (5556)
(let [host "127.0.0.1"]
(tcp server {:host host})
(udp-server {:host host})
(ws-server {:host host}))

; Expire old events from the index every 5 seconds.
(periodically-expire 5)

(let [index (index)]
; Inbound events will be passed to these streams:
(streams
(default :ttl 60
; Index all events immediately.
index

; Log expired events.
(expired
(fn [event] (info "expired" event))))))



Цей файл розділений на кілька розділів. Кожний розділ починається з коментаря, позначуваного, як це прийнято в Clojure, крапкою з комою (;).

У першому розділі вказано файл, який будуть записуватися логи. Далі йде розділ з зазначенням інтерфейсів. Зазвичай Riemann слухає на TCP, UDP — і вебсокет-інтерфейсі. &Nbsp;замовчуванням усі вони прив'язані до локального хоста (127.0.0.1).

Наступний розділ містить налаштування для подій і індексу:

(periodically-expire 5)

(let [index (index)]
; Inbound events will be passed to these streams:
(streams
(default :ttl 60
; Index all events immediately.
index


Перша функція (periodically-expire) прибирає з індексу всі події, у яких закінчився період актуальності, і присвоює їм статус expired. Очищення подій відбувається кожні 5 секунд.

&Nbsp;замовчуванням Riemann копіює в події вичерпаним терміном актуальності поля :service :host. Можна з копіювати і інші поля; для цього потрібно з функцією periodically-expired використовувати опцію :key-keys. Ось так, наприклад, ми можемо дати вказівку зберігати не тільки ім'я хоста і ім'я сервісу, але і теги:

(periodically-expire 5 {:keep-keys [:host :service :tags]})


Далі слід конструкція, якою ми визначаємо символ ім'ям index. Значення цього символу   index, тобто це функція, яка відправляє події індекс. Вона використовується, щоб вказати Riemann, коли індексувати то чи іншу подію.

З допомогою функції streams ми описуємо потоки. Кожен потік являє собою функцію, що приймає в якості аргументу подія. Функція streams вказує Riemann: «ось список функцій, які потрібно викликати при додаванні нових подій». Усередині цієї функції ми встановлюємо TTL для подій   60 секунд. Для цього ми скористалися функцією default, яка бере поле з події і дозволяє встановити для нього значення за замовчуванням. Події, у яких немає TTL, буде отримувати статус expired.

Потім дефолтна конфігурація викликає символ index. Це означає, що всі вступники події будуть додаватися в індекс автоматично.

Заключний розділ містить вказівку логгировать події статусом expired:

; Log expired events.
(expired
(fn [event] (info "expired" event))))))


Внесемо в конфігураційний файл деякі зміни. У розділі, присвяченому мережевим інтерфейсам, замінимо 127.0.0.1 на 0.0.0.0, щоб Riemann міг приймати події з будь-якого хоста.

У самий кінець файлу додамо:

;print events to the log
(streams
prn

#(info %))


Це функція prn, яка буде записувати події в логи і у стандартний вивід. Після цього збережемо внесені зміни і перезапустим Riemann.

У ситуації, коли доводиться відслідковувати роботу безлічі сервера, можна створювати не загальний конфігураційний файл, а цілу директорію з окремими файлами для кожного сервера або групи серверів (див. рекомендації цієї статті).

З детальною інструкцією по написанню конфігураційного файлу можна познайомитися тут.

Надсилання даних в Riemann

Спробуємо тепер надіслати дані Riemann. Скористаємося для цього клієнтом riemann-health, який входить в вже встановлений нами раніше пакет riemann-tools. Відкриємо ще одну вкладку терміналу і виконаємо:

$ riemann-health


Ця команда передає Riemann дані про стан хоста (завантаження CPU, обсяг зайнятого дискового простору, об'єм використовуваної пам'яті).
Riemann почне приймати події. Інформація про ці події буде записуватися у файл /var/log/riemann/riemann.log. Вона представлена в наступному вигляді:

#riemann.codec.Event{:host "cs25706", :service "disk /", :state "ok", :description "8% used", :metric 0.08, :tags nil, :time 1456470139, :ttl 10.0}
INFO [2016-02-26 10:02:19,571] defaultEventExecutorGroup-2-1 - riemann.config - #riemann.codec.Event{:host cs25706, :service disk /, :state ok :description 8% used, :metric 0.08, :tags nil, :time 1456470139, :ttl 10.0}
#riemann.codec.Event{:host "cs25706", :service "load", :state "ok", :description "1-minute load average/core is 0.02", :metric 0.02, :tags nil, :time 1456470139, :ttl 10.0}


Riemann-health — це лише одна з утиліт в пакет riemann-tools. У нього входить досить велика кількість утиліт для збору метрик: riemann-net (для моніторингу мережевих інтерфейсів), riemann-diskstats (для моніторингу підсистеми вводу-виводу), riemann-proc (для моніторингу процесів в Linux) і інші. З повним списком утиліт можна ознайомитися тут.

Створюємо першу перевірку

Отже, Riemann встановлений і запущений. Тепер спробуємо створити першу перевірку. Відкриємо конфігураційний файл і додамо в нього такі рядки:

(let [index (index)] 
(streams 
(default :ttl 60 
index 
;#(info %) 
(where (and (service "disk /") (> metric 0.10)) 
#(info "Disk space on / is over 10%!" %)) 


Перед функцією (#info) стоїть знак коментаря   крапка з комою (;). Це зроблено, щоб Riemann не записував кожне подія в лог. Далі ми описуємо потік where. У нього потрапляють події, які відповідають заданому критерію. У нашому прикладі таких критеріїв два:

  • в полі :service повинно мати значення disk /;
  • значення поля :metric повинно бути більше 0.10 або 10%.


Потім вони передаються в дочірній потік для подальшої обробки. У нашому випадку інформація про таких подіях буде записуватися в файл /var/log/riemann/riemann.log.

Фільтрація: коротка довідка

Без фільтрації подій повноцінна робота c Riemann неможлива, тому про ній варто сказати кілька слів окремо.

Почнемо з фільтрації подій з допомогою регулярних виразів. Розглянемо наступний приклад опису потоку where:

where (service #"^nginx")) 


У Clojure регулярні вирази позначаються знаком #, полягають в подвійні лапки. У нашому прикладі в потік where будуть потрапляти вирази, які містять ім'я nginx в поле :service.

Події в потоці where можна поєднувати з допомогою логічних операторів:

(where (and (tagged "www") (state "ok"))) 


У цьому прикладі в потік where будуть потрапляти події з тегом www і значенням ok в поле state. Вони об'єднуються з подіями з потоку tagged.
Tagged — це скорочене ім'я функції tagged-all, яка об'єднує всі події з заданими тегами. Є ще функція tagged-any — вона об'єднує в потік події, зазначені одним або декількома з зазначених тегів:

(tagged-any ["www" "app1"] #(info %)) 


У нашому прикладі в потік tagged потраплять події, зазначені тегами www і app1.

&Nbsp;відношенню до подіям можна виконувати математичні операції, наприклад:

(where (and (tagged "www") (>= (* metric 10) 5)))


У цьому прикладі події будуть потрапляти події з тегом www, у яких значення поля :metric, помножене на 10, буде більше 5.
Аналогічний синтаксис можна використовувати, щоб вибирати події, у яких значення у поле :metric потрапляють в зазначений діапазон:

(where (and (tagged "www") (< 5 metric 10)))



У наведеному прикладі в потік where будуть потрапляти події з тегом www, у яких значення поля :metric знаходиться в діапазоні 5  10.

Настройка повідомлень

Riemann може розсилати повідомлення у у разі відповідності заданим умовам перевірок. Почнемо з налаштування сповіщень по електронній пошті. У Riemann для цього використовується функція email:

[
(def email (mailer {:from "riemann@example.com"}))

(let [index (index)]
; Inbound events will be passed to these streams:
(streams
(default :ttl 60
; Index all events immediately.
index

(changed-state {:init "ok"}
(email "andrei@example.com")))))


Розсилання повідомлень у Riemann здійснюється на базі спеціальної бібліотеки Clojure   Postal. &Nbsp;замовчуванням для розсилки використовується локальний поштовий сервер.
Всі повідомлення будуть відправлятися з адреси виду riemann@example.com.

Якщо локальний поштовий сервер не встановлено, Riemann буде видавати повідомлення про помилку виду:

riemann.email$mailer$make_stream threw java.lang.NullPointerException


У наведеному вище прикладі коду ми використовували ярлик changed-state і тим самим вказали, що Riemann повинен відслідковувати події, стан яких змінився. Значення змінної init повідомляє Riemann, яким було початковий стан події. Всі події, стан яких змінився з ok на яке-небудь інше, будуть передаватися функції email. Інформація про таких подіях буде відправлена на вказану адресу електронної пошти.
З більш докладними прикладами налаштування сповіщень можна ознайомитися статті Джеймса Тернбулла, одного з розробників Riemann.

Візуалізація метрик: riemann-dash

У Riemann є власний інструмент для візуалізації метрик і побудови простих дашбордов   riemann-dash. Встановити його можна так:

$ git clone git://github.com/aphyr/riemann-dash.git
$ cd riemann-dash
$ bundle


Запускається riemann-dash з допомогою команди:

$ riemann-dash


Домашня сторінка riemann-dash доступна в браузері за адресою [ip-адреса сервера]:4567:

riemann-dash

Підведемо до чорної написи Riemann в самому центрі, натиснемо клавішу Ctrl (на Mac   cmd) і гукнемо по нею. Напис буде виокремлено сірим кольором. Після цього натиснемо на клавішу E, щоб приступити до редагування:

riemann-dash

У випадаючому меню title виберемо пункт Grid, а в поле query напишемо true:

riemann-dash

Встановивши необхідні налаштування, натиснемо на кнопку Apply:

riemann-dash

Дашборд виходить не дуже естетичний і зручний, але цілком наочний. Незручність, проте, компенсується тим, що з Riemann можна використовувати сторонні інструменти візуалізації, d зокрема Graphite і Grafana — заитересованный читач без праці зможе знайти відповідні публікації в Інтернеті. А процедуру налаштування зв'язки Riemann+InfluxDB+Grafana ми розповімо в наступному розділі.

Надсилання даних в InfluxDB

Безперечною перевагою Riemann є широкі можливості інтеграції. Зібрані з його допомогою метрики можна відправляти в сторонні сховища. Нижче ми покажемо, як інтегрувати Riemann c InfluxDB налаштувати візуалізацію даних з допомогою Grafana.

Встановимо InfluxDB:

$ wget https://s3.amazonaws.com/influxdb/influxdb_0.9.6.1_amd64.deb
$ sudo dpkg -i influxdb_0.9.6.1_amd64.deb


Про конфигурированиии InfluxDB можна детальніше почитати офіційній документації, а також одній з наших попередніх статей.

По завершенні установки виконаємо команду:

$ sudo /etc/init.d/influxdb start


Потім створимо базу для зберігання даних з Riemann:

$ sudo influx

>CREATE DATABASE riemann


Створимо для цієї бази користувача і встановимо для нього пароль:

>CREATE USER riemann WITH PASSWORD 'пароль користувача riemann'
>GRANT ALL ON riemann TO riemann


Ось і все, установка і базова настройка InfluxDB завершені. Тепер потрібно прописати необхідні налаштування конфігураційному файлі Riemann (код взято звідси незначно модифікований):

; -*- mode: clojure; -*-
; vim: filetype=clojure

;підключаємо capacitor, клієнт для роботи з InfluxDB
(require 'capacitor.core)
(require 'capacitor.async)
(require 'clojure.core.async)

(defn make-async-influxdb-client [opts]
(let [client (capacitor.core/make-client opts)
events in (capacitor.async/make-chan)
resp-out (capacitor.async/make-chan]
(capacitor.async/run! events-in resp-out client 100 10000)
(fn [series payload]
(let [p (merge payload {
:series series
:time (* 1000 (:time payload)) ;; s → ms
})]
(clojure.core.async/put! events-in p)))))

(def influx (make-async-influxdb-client {
:host "localhost"
:port 8086
:username "riemann"
:password "пароль користувача riemann"
:db "riemann"
}))

(logging/init {:file "/var/log/riemann/riemann.log"})


(let [host "0.0.0.0"]
(tcp server {:host host})
(udp-server {:host host})
(ws-server {:host host}))

(periodically-expire 60)

(let [index (index)]
(streams
index

(fn [event]
(let [series (format "%s.%s" (:host event) (:service event))]
(influx series {
:time (:time event)
:value (:metric event)
})))))


Збережемо внесені зміни і перезапустим Riemann.

Після цього встановимо Grafana:

$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
$ sudo dpkg -i grafana_2.6.0_amd64.deb


Докладних інструкцій з налаштування Grafana ми приводити не та в і немає особливої потреби: відповідні публікації можна без зусиль знайти в Інтернеті.

Домашня сторінка Grafana буде доступна в браузері за адресою http://[IP-адреса сервера]:3000. Далі потрібно лише додати нове джерело даних (InfluxDB) і створити дашборд.

Висновок

У цій статті ми представили короткий огляд можливостей Riemann. Ми торкнулися наступні теми:

  • особливості мови Clojure;
  • установка і первинна настройка Riemann;
  • структура конфігураційного файлу і особливості його синтаксису;
  • створення перевірок;
  • настройка повідомлень;
  • візуалізація метрик з допомогою riemann-dash
  • інтеграція Riemann c InfluxDB і візуалізація метрик з допомогою Grafana


Якщо вам здається, що ми упустили якісь важливі деталі   напишіть нам, і  доповнимо огляд. А якщо ви використовуєте Riemann на практиці, запрошуємо поділитися досвідом у коментарях.

Якщо ви з тих чи інших причин не можете залишати коментарі тут — ласкаво просимо у наш корпоративний блог.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.