Zabbix: мониторим всё подряд (на примере Redis'а)

Kate

Administrator
Команда форума
Zabbix — замечательный продукт для администраторов крупных программно-аппаратных комплексов. Он настолько хорош, что может использоваться не только крупным бизнесом, но и средне-малым бизнесом, и даже в pet-проекте. В общем, у меня есть небольшой опыт работы с Zabbix'ом и я смело могу рекомендовать его к использованию.
Правда я не могу сказать, что понимаю "философию Zabbix'а". Несмотря на обширную подробную документацию на русском языке, мне было сложно погружаться в мир Zabbix'а — создавалось ощущение, что мы с разработчиками одни и те же вещи называем разными именами. Возможно потому, что Zabbix создавался админами для админов, а я всё-таки больше разработчик и пользователь.
Тем не менее, для запуска Zabbix'а и для мониторинга основных параметров компьютерных систем (процессор, память и т.п.) навыков обычного linux-пользователя хватает. Есть большое количество плагинов от сторонних разработчиков, расширяющих возможности Zabbix'а. Для моих нужд мне потребовалось настроить мониторинг Redis-сервера. Я немного покопался в коде имеющихся плагинов и на их примере выяснил, что архитектура Zabbix'а позволяет достаточно просто подключать к мониторингу любые параметры информационных систем, которые могут быть выражены в числовом виде.
Под катом — пример Zabbix-плагина с моим пояснением по терминологии Zabbix'а. Кому-то этот пример покажется наивным, ну а кому-то поможет проще освоиться с понятиями. В любом случае, Zabbix достаточно велик для того, чтобы ощупать его с разных сторон.

Базовые понятия​

Кратко о некоторых понятиях, которые используются в Zabbix'е: agents, items, triggers, actions, notifications, templates.

Сервер и агенты​

С точки зрения пользователя Zabbix делится на две большие части: сервер и агенты. Сервер располагается на одной машине, которая собирает и хранит статистические данные, а агенты — на тех машинах, данные с которых собираются:
Zabbix server and agents

Параметры мониторинга​

Любая величина, которая может выражена в числовом или строковом виде, называется в терминологии Zabbix'а — элементом данных (item). Каждый элемент связывается с уникальным ключом (именем). Вот примеры элементов данных:
  • system.cpu.load[percpu,avg1]: 0.1167
  • system.uname: "Linux supru 4.15.0-50-generic #54-Ubuntu SMP Mon May 6 18:46:08 UTC 2019 x86_64"
Значения этих элементов данных (параметров мониторинга) привязываются ко времени, история значений параметров сохраняется в базе сервера.

События​

При наступлении некоторого события в Zabbix'е срабатывает триггер. Например,
  • {system.cpu.load[percpu,avg1].avg(5m)}>10 — среднее значение параметра за последние 5 минут превысило "10"
  • {system.uname.diff(0)}>0 — текущее значение параметра не равно предыдущему значению
По сути, триггеры — это формулы, в которых переменными выступают параметры мониторинга (текущие и сохранённые), и которые на выходе дают true/false.

Действия и Оповещения​

В случае наступления события (срабатывания тригера) сервер может выполнить действие. Например, отправить оповещение по email'у на заданный адрес ("Problem: host is unreachable for 5 minutes"). Также действие может быть выполнено в случае возвращения триггера в исходное состояние ("Resolved: host is unreachable for 5 minutes"). Все события (переключения триггера) логируются на стороне сервера.

Шаблоны​

Zabbix даёт возможность как настроить правила мониторинга для отдельного хоста, так и создать шаблон правил (template), который можно применять к различным хостам:
zabbix templates

На примере видно, что шаблон "Template App SSH Service" описывает одно приложение (Applications), один параметр мониторинга (Items), один триггер (Triggers). Также доступны описания для графиков, экранов, правил обнаружения и web-сценариев.

Постановка задачи для плагина​

Начальное положение​

Сам Zabbix предлагает свой собственный плагин для мониторинга состояния Redis'а, но на моей версии сервера (4.2.8) мне не удалось его задействовать (плагин для версии 4.4 и выше). Также предлагаются решения от третьих лиц (около десятка вариантов под различные версии Zabbix'а, на картинке только первых три):
Redis plugins for Zabbix

Каждый из них обладал своими плюсами-минусами, пришлось заглянуть внутрь, чтобы выбрать. Лучшим, на мой взгляд, оказался плагин Shakeeljaveed/zabbix-redis-userparamaters, состоявший из двух файлов:
  • README.md
  • redis-userparameter.conf
Немножко пришлось поработать "ручками", но зато на его примере стало чуть понятнее, как данные от агента попадают на сервер. По предложению автора Javeed Shakeel состояние Redis'а каждые 2 минуты сбрасывалось кроном в файл /tmp/redismetric:
*/2 * * * * /usr/bin/redis-cli info > /tmp/redismetric

А затем каждый параметр мониторинга извлекался агентом из файла /tmp/redismetric при помощи средств самой операционной системы. Инструкции для этого размещались в конфигурации Zabbix-агента /etc/zabbix/zabbix_agent.conf.d/userparameter_redis.conf. Например, вот так выглядят инструкция для извлечения параметра used_memory (использование памяти Redis-сервером):
UserParameter=used_memory,grep -w 'used_memory' /tmp/redismetric | cut -d: -f2

То есть, в файле /tmp/redismetric с выводом redis-cli INFO по ключу used_memory ищется строка (grep -w ...)
used_memory:7153216

которая затем разбивается на столбцы по разделителю ":" (cut -d: -f2). На выходе агент получает число 7153216 и присваивает его параметру used_memory.
Остаётся через web-интерфейс настроить сервер, чтобы он периодически отправлял запросы агенту на получение данных по параметру used_memory, после чего данные начинают литься на сервер, сохраняться в базе, по ним можно строить графики и создавать триггера, реагирующие на изменения этого параметра.

Цель​

Задачей мониторинга состояния любой системы явлется не только сбор статистики, но и предупреждение о возникновении ситуаций, требующих вмешательства человека. Так как с Redis'ом я работаю на уровне очень начинающего пользователя, то пришлось поискать информацию, на какие параметры "здоровья" обращать внимание и что они значат. Наиболее достойной показалась статья "6 Crucial Redis Monitoring Metrics You Need To Watch". Проанализировав её, я пришёл к выводу, что "для полного счастья" мне нужно собирать данные для обнаружения следующих событий:
  • Memory fragmentation: used_memory_rss / used_memory > 1.5
  • Low cache hit ratio: (keyspace_hits)/ (keyspace_hits + keyspace_misses) < 0.8
  • Rejected connections: rejected_connections > 0
  • Evicted keys: evicted_keys > 0
Также я хотел собирать статистику по дополнительным параметрам (версия Redis'а, uptime и т.п.). В общем, имея общее представление о том, каким образом данные собираются агентом и передаются на сервер, "хотелки" можно сильно не ограничивать. В итоге получился список параметров для мониторинга из 12 позиций.

Создание собственного плагина​

Параметры мониторинга​

Плагин, который я анализировал, предполагал выполнение отдельной команды для получения отдельного параметра (элемента данных, item'а):
grep -w 'used_memory' /tmp/redismetric | cut -d: -f2

Т.е., для получения данных по 12 параметрам агент должен будет 12 раз выполнить различные наборы команд. А если мне нужно мониторить параметры, которые сложно извлечь цепочкой команд и нужно будет писать отдельный shell-скрипт или полноценную программу? Для таких "хотелок" Zabbix предлагает вариант с зависимыми элементами данных. Суть его в том, что на стороне агента скриптом формируется набор данных (например, в формате JSON), который передаётся на сервер в виде строкового параметра. Затем на стороне сервера происходит разбор полученных данных и вычленение из них отдельных элементарных параметров.

Основной элемент данных​

Я описал основной элемент данных redis.info строкового типа с периодом обновления в 1 мин., без сохранения истории изменений:
base item

Предположительно, на стороне агента должен генерироваться такой JSON:
{
"version": "4.0.9",
"uptime": 1897336,
"used_memory": 1054943416,
"used_memory_rss": 1138159616,
"keyspace_hits": 75810274,
"keyspace_misses": 13545949,
"connected_clients": 15,
"rdb_last_save_time": 1580126954,
"total_connections_received": 1258614,
"rejected_connections": 0,
"expired_keys": 60270,
"evicted_keys": 0
}

после чего этот текст должен попадать на сервер в виде элемента данных redis.info, но не сохраняться, а служить базой для других элементов данных (параметров мониторинга).

Зависимый элемент данных​

Тестовый параметр redis.info.version зависит от redis.info и сохраняет свои значения в базе в течение 90 дней. Периодичность мониторинга параметра зависит от базового элемента (redis.info):
dependent item (base)

Значение параметра redis.info.version извлекается из значения redis.info при помощи инструкций JSONPath:
dependent item (preprocess)

По аналогичной схеме описываются остальные зависимые элементы данных (параметры мониторинга), которые передаются в виде JSON'а. Вот пример описания числового параметра redis.info.used_memory:
dependent number item (base)

Всё достаточно прозрачно, за исключением Units и Trend storage period. Со вторым пунктом я не разбирался, оставил по-умолчанию, а единицы измерения объяснены в документации. В данном случае значение redis.info.used_memory измеряется в байтах и в web-интерфейсе сворачивается до кило/мега/гига/...-байт.
Формула для извлечения значения из JSON'а: JSONPath = $.used_memory

Вычисляемый элемент данных​

Для вычисления фрагментации памяти используется отношение used_memory_rss / used_memory и на его базе определяется триггер, срабатывающий при превышении отношением значения 1.5. В Zabbix'е есть вычисляемый тип элементов данных:
calc item

Значение для параметра redis.info.used_memory_ratio вычисляется каждую минуту на основании последних значений двух других параметров (redis.info.used_memory_rss и redis.info.used_memory), сохраняется в базе в течение 90 дней и т.д.

Триггеры​

Вот пример триггера, срабатывающего при излишней фрагментации памяти:
bl81ojowbfvanebjn9nefzoh29w.png

Ничего необычного, за исключением формата выражений, используемого в формуле изменения состояния триггера. В Zabbix'е есть конструктор форм, можно воспользоваться им или обратиться к документации/примерам (список триггеров доступен через web-интерфейс по адресу "Configuration / Templates / ${TemplateName} / Triggers").
Триггер может базироваться на любых элементах данных (item'ах) вне зависимости от их типа (основной, зависимый, вычисляемый).

Настройка агента​

Генерация JSON'а​

Для получения значений параметров мониторинга и формирования JSON'а я использую вот такой shell-скрипт:
#!/bin/bash
## ===========================================================================
# Script to generate Redis monitoring data in JSON format
# for 'zabbix-agent'.
## ===========================================================================
# collect working variables/data
BIN_REDIS=$(whereis -b redis-cli | cut -d" " -f2) # /usr/bin/redis-cli
DATA_INFO=$(${BIN_REDIS} INFO | tr -d '\r') # get info and remove trailing '\r' from output

##
# Extract stats and save it into env. vars.
##
# find lines with 'grep', cut second field after ":" and put it into env. variable:
ITEM_VERSION=$(grep "^redis_version:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_UPTIME=$(grep "^uptime_in_seconds:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_USED_MEMORY=$(grep "^used_memory:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_USED_MEMORY_RSS=$(grep "^used_memory_rss:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_KEYSPACE_HITS=$(grep "^keyspace_hits:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_KEYSPACE_MISSES=$(grep "^keyspace_misses:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_CONNECTED_CLIENTS=$(grep "^connected_clients:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_RDB_LAST_SAVE_TIME=$(grep "^rdb_last_save_time:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_TOTAL_CONNECTIONS_RECEIVED=$(grep "^total_connections_received:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_REJECTED_CONNECTIONS=$(grep "^rejected_connections:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_EXPIRED_KEYS=$(grep "^expired_keys:" <<<"${DATA_INFO}" | cut -d: -f2)
ITEM_EVICTED_KEYS=$(grep "^evicted_keys:" <<<"${DATA_INFO}" | cut -d: -f2)

# compose output JSON for Zabbix server:
echo -n "{"
echo -n "\"version\": \"${ITEM_VERSION}\","
echo -n "\"uptime\": ${ITEM_UPTIME},"
echo -n "\"used_memory\": ${ITEM_USED_MEMORY},"
echo -n "\"used_memory_rss\": ${ITEM_USED_MEMORY_RSS},"
echo -n "\"keyspace_hits\": ${ITEM_KEYSPACE_HITS},"
echo -n "\"keyspace_misses\": ${ITEM_KEYSPACE_MISSES},"
echo -n "\"connected_clients\": ${ITEM_CONNECTED_CLIENTS},"
echo -n "\"rdb_last_save_time\": ${ITEM_RDB_LAST_SAVE_TIME},"
echo -n "\"total_connections_received\": ${ITEM_TOTAL_CONNECTIONS_RECEIVED},"
echo -n "\"rejected_connections\": ${ITEM_REJECTED_CONNECTIONS},"
echo -n "\"expired_keys\": ${ITEM_EXPIRED_KEYS},"
echo -n "\"evicted_keys\": ${ITEM_EVICTED_KEYS}"
echo -n "}"

Этот скрипт я поместил в файл /var/lib/zabbix/user_parameter/redis/get_info.sh на сервере с Redis'ом, на котором уже установлен агент Zabbix'а. Пользователь, под которым запускается Zabbix-агент (обычно zabbix) должен иметь права на выполнение файла get_info.sh.

Файл userparameter_XXX.conf​

На стороне агента дополнительные параметры мониторинга прописываются в файлах userparameter_*.conf в каталоге /etc/zabbix/zabbix_agentd.d. Поэтому для того, чтобы агент узнал о том, каким образом ему нужно собирать данные по параметру redis.info, я создал файл /etc/zabbix/zabbix_agentd.d/userparameter_redis.conf с таким содержимым:
UserParameter=redis.info,/var/lib/zabbix/user_parameter/redis/get_info.sh

Т.е., для получения данных по параметру redis.info агент должен запустить скрипт /var/lib/zabbix/user_parameter/redis/get_info.sh и передать на сервер результат выполнения.
После рестарта Zabbix-агента (sudo service zabbix-agent restart) у него появляется возможность собирать данные для параметра redis.info и отправлять их на сервер.
UPDATE: коллега banzayats обратил внимание, что текстовые данные с хоста можно получить без создания промежуточного скрипта userparameter_*.conf — при помощи параметра "system.run" и проводить постпроцессинг уже на стороне zabbix-сервера.

Резюме​

Понимание Zabbix'а ко мне приходило (и всё ещё приходит) достаточно тяжело. Тем не менее я считаю его прекрасным инструментом, особенно после того, как для меня открылась простота добавления собственных параметров мониторинга (элементов данных). По большому счёту, достаточно добавить один файл на сервер с агентом (userparameter_XXX.conf) с shell-командой для сбора данных и настроить Zabbix-сервер на получение этих данных через web-интерфейс. И всё — можно накапливать данные, строить графики, анализировать изменения и создавать триггера, реагирующие на эти изменения.
Код шаблона, файла userparameter_redis.conf и скрипта get_info.sh можно посмотреть в проекте flancer32/zabbix_plugin_redis.
Спасибо всем, кто дочитал до конца, а особенно тем, кто нашёл в публикации что-то полезное для себя.



Источник статьи: https://habr.com/ru/post/485538/
 
Сверху