Open source
12 December 2013

Sensu — фреймворк для мониторинга

Tutorial


Немного истории

В 2011 году в DevOps-среде возникло движение, объединившееся под хештегом #monitoringsucks, и критиковавшее существующие системы мониторинга за отсутствие гибкости. Что именно их не устраивало — прекрасно иллюстрирует эта презентация.
Если вкратце — хочется людям некоего стандарта API для взаимодействия между компонентами мониторинга, ну и появления самих этих компонент, чтоб из них строить гибкий и умный мониторинг.

Итогом этой волны недовольства стали массовые обсуждения проблем и привлечение внимания к интересным утилитам типа Sensu и Riemann.

В 2013 году хештег в сообществе сменился — теперь это #monitoringlove. Произошло это благодаря развитию opensource-утилит для мониторинга.

Из новых утилит наибольший интерес представляет Sensu. Riemann я не стал всерьез рассматривать, поскольку на данный момент у него нет никаких средств для обеспечения отказоустойчивости, да и сама идея писать конфиг на Clojure мне не сильно нравится.

Именно о Sensu я и расскажу в этой статье, опишу базовые принципы работы и приведу пример решения типичной задачи мониторинга.

Основные факты о Sensu:

* Написан на Ruby, использует EventMachine (я бы предпочел Python, но ладно).
* Конфиги в JSON
* Может использовать плагины от Nagios.
* Работает через RabbitMQ, в PUSH-режиме, когда клиенты сами шлют серверу
результаты проверок по мере готовности.
* Есть пакеты DEB, RPM и даже MSI.
* Есть модули для puppet и cookbook для Chef.

На изображении ниже представлена схема работы Sensu. На мой взгляд, все очень логично, и такая схема работы дает масштабирование и отказоустойчивость «из коробки».



Система состоит из трех основных компонентов: sensu-server, sensu-api, и на клиентах sensu-client. Также доступна sensu-dashboard. Установка тривиальна и подробно освещена в документации, для последней на данный момент версии 0.12 она доступна тут. Как я уже упоминал, есть deb, rpm и msi пакеты.

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


Для того, чтобы понять, как все это работает, надо разобраться в терминологии. Я не ставлю целью перевод официальной документации, а хочу дать базовые понятия, чтоб было понятно, о чем будет в дальнейшем идти речь.

У нас есть следующие сущности:

Клиент (Client)

Это некий сервер с установленным и настроенным sensu-client, который публикует информацию о себе в RabbitMQ и таким образом регистрируется в системе мониторинга Sensu. От сервера Sensu он получает набор проверок, и выполняет их, складывая результат в RabbitMQ.

Для самоидентификации ему нужна конфигурация, которая выглядит примерно так (взято из документации):

{
  "client": {
    "name": "i-424242",
    "address": "127.0.0.1",
    "subscriptions": [
      "production",
      "webserver",
      "mysql"
    ]
  }
}


Все довольно очевидно, за исключением «подписок» (subscriptions). Подписки представляют собой список ролей, ассоциированных с этим сервером, и определяют список выполняющихся на нем проверок. Более тонкая настройка описана в официально документации, из полезного можно добавить любые поля, значения из которых можно будет использовать в проверках, а также интервал времени, который должен пройти для генерации события об уходе клиента в оффлайн.

Проверка (Check)

Проверки определяют команды, которые будут запускаться на клиентах, и их параметры. Полностью совместимы с плагинами Nagios, т.е. используют exit code как критерий успешности проверки, а STDOUT или STDERR как источник данных. Проверки настраиваются в конфигурации sensu-server, типичная проверка выглядит так (пример из документации):

{
  "checks": {
    "chef_client": {
      "command": "check-chef-client.rb",
      "subscribers": [
        "production"
      ],
      "interval": 60
      "handlers": [
        "pagerduty",
        "irc"
      ]
    }
  }
}


Из интересного тут опять-таки подписки и хендлеры. Подписки определяют, на каких клиентах будет эта команда запущена.

А набор хендлеров определяют список команд, которые будут выполнены при обработке данных от этой проверки. О них мы дальше поговорим.

Стоит отметить, что проверка может быть «метрикой» (metric), т.е. данные из ее STDOUT будут всегда просто передаваться в хендлеры. Таким образом можно слать данные метрик куда-нибудь для хранения или рисования графиков (например, в Graphite). Подробности в документации.

Хендлеры (Handlers)

Хендлеры определяют команды, которые будут запускаться на сервере мониторинга при поступлении данных от проверок, и их параметры. Например, этот хендлер при получении от какой-либо проверки не-нулевого exit code выполнит команду mail -s 'sensu event' email@address.com (пример из документации):

{
  "handlers": {
    "mail": {
      "type": "pipe",
      "command": "mail -s 'sensu event' email@address.com"
    }
  }
}


Тут все очевидно, хендлеров в репозитории плагинов куча. Можно слать в Pagerduty, и письма отправлять, и в Graylog2 слать в gelf. Подробности в документации.

Всего вышеперечисленного уже достаточно, чтобы соорудить работающую систему. Есть еще мутаторы, расширения и API, но это нам сейчас не важно.

Приступаем к самому интересному


Sensu позиционируется именно как «фреймворк для мониторинга», и это значит, что «из коробки» в нем ничего привычного по энтерпрайз-системам типа Zabbix нет. Вся функциональность добавляется благодаря плагинам.

Попробуем сделать что-нибудь полезное. Возьмем простую задачу — выполнять проверки относительно Redis на клиентах, в случае проблем выводить алерт на панель Dashing, а также для истории слать сообщение в Graylog2 и email на адрес admin@example.com. А еще снимать метрики с Redis и отправлять на хранение в Graphite, а потом по агрегированным значениям keys тоже выполнять проверки.

Клиенты имеют адреса 192.168.1.2N, Graphite развернут на 192.168.1.80:8082, RabbitMQ и Redis тоже на 192.168.1.80. Graylog2 слушает на 192.168.1.81, там же развернута Dashing.

Конфигурация


Начнем с конфигурации клиентов.

Допустим, у нас есть N серверов в роли redis.

Конфигурация клиента выглядит так:

/etc/sensu/config.json
{
  "client": {
    "graphite_server": "192.168.1.80:8082",
    "address": "192.168.1.2N",
    "name": "clientN",
    "subscriptions": [
      "redis"
    ]
  }
  "rabbitmq": {
    "vhost": "/sensu",
    "host": "192.168.1.80",
    "password": "password",
    "port": 5672,
    "user": "sensu"
  }
}


и размещается на каждом из N клиентов.

Все остальные файлы конфигураций только на сервере Sensu.

Основные настройки:

/etc/sensu/conf.d/settings.json

{
  "api": {
    "host": "192.168.1.80",
    "port": 4567
  },
  "redis": {
    "host": "192.168.1.80",
    "port": 6379
  },
  "rabbitmq": {
    "vhost": "/sensu",
    "host": "192.168.1.80",
    "password": "password",
    "port": 5672,
    "user": "sensu"
  },
  "mailer": {
    "mail_from": "sensu@example.com",
    "smtp_port": "25",
    "mail_to": "admin@example.com",
    "smtp_address": "localhost"
  },
  "dashing": {
    "auth_token": "YOUR_AUTH_TOKEN",
    "host": "http://192.168.1.81:8088"
  },
  "gelf": {
    "server": "192.168.1.81"
    "port": "12201",
  }
}


Как вы видите, мы настроили не только сам Sensu, но и параметры для хендлеров dashing, gelf и mailer.

Теперь определим сами эти хендлеры:

/etc/sensu/conf.d/handlers.json
{
  "handlers": {
    "default": {
      "type": "set",
      "handlers": [
        "mailer",
        "dashing",
        "gelf"
      ]
    },
    "gelf": {
      "type": "pipe",
      "command": "/etc/sensu/handlers/gelf.rb"
    },
    "mailer": {
      "type": "pipe",
      "command": "/etc/sensu/handlers/mailer.rb"
    },
    "dashing": {
      "type": "pipe",
      "command": "/etc/sensu/handlers/dashing.rb"
    },
    "graphite": {
      "mutator": "only_check_output",
      "type": "amqp",
      "exchange": {
        "durable": true,
        "type": "topic",
        "name": "metrics"
      }
    }
  }
}


Тут все просто. Заметьте, что в Graphite мы данные шлем через AMQP. Хендлеры надо разложить на сервере мониторинга в /etc/sensu/handlers.

Теперь настроим проверки, которые будут выполняться на клиентах:

/etc/sensu/conf.d/checks.json
{
  "checks": {
    "redis_processes": {
      "interval": 60,
      "command": "/etc/sensu/plugins/processes/check-procs.rb -p redis -c 8 -C 0 -w 7 -W 1",
      "subscribers": [
        "redis",
      ],
      "handlers": [
        "default"
      ]
    },
    "redis_memory": {
      "dependencies": [
        "redis_processes"
      ],
      "command": "/etc/sensu/plugins/redis/check-redis-memory.rb -c 204800 -w 51200",
      "interval": 60,
      "subscribers": [
        "redis",
      ],
      "handlers": [
        "default"
      ]
    },
    "redis_metric": {
      "handlers": [
        "graphite"
      ],
      "interval": 60,
      "dependencies": [
        "redis_processes"
      ],
      "command": "/etc/sensu/plugins/redis/redis-graphite.rb --scheme stats.:::name:::.redis",
      "subscribers": [
        "redis",
      ],
      "type": "metric"
    },
    "redis_keys_from_graphite": {
      "interval": 60,
      "command": "/etc/sensu/plugins/graphite/check-data.rb -s :::graphite_server::: -t stats.:::name:::.redis.db0.keys -w 500 -c 900 -a 120",
      "subscribers": [
        "redis"
      ],
      "dependencies": [
        "redis_processes"
      ],
      "handlers": [
        "default"
      ]
    }
  }
}


Проверки осуществляются плагинами Sensu, которые надо разложить на клиентах в /etc/sensu/plugins. Для знакомых с Nagios тут ничего нового, интересна только метрика redis_metric, из которой мы в Graphite данные кладем, а потом в проверке redis_keys_from_graphite достаем и проверяем данные за последние 10 минут. Вообще, почти каждый плагин имеет ключ --help, который выдает вполне вменяемую справку по использованию.

Вот и вся конфигурация. Все наглядно, все можно хранить в репозитории, и это прекрасно.

Конечно, надо настроить еще Dashing и Graphite, но это я оставлю за рамками статьи. Инструкция по настройке Sensu + Graphite можно найти тут, а с Dashing все и так понятно.

А еще у Sensu есть простенький dashboard, на котором можно увидеть список клиентов, проверок, и сработавших алертов. Через API и с помощью dashboard можно выключать генерацию алертов для любых хостов или проверок, а также видеть общее состояние системы.
Выглядит он как-то так (скрин не мой):


Выводы


Как мы видим, Sensu берет на себя только роль маршрутизатора и организатора, а вся грязная работа делается внешними программами. Это позволяет сохранять небольшой размер исходного кода, и общую простоту системы. Регистрация клиентов через RabbitMQ позволяет избавиться от механизма «обнаружения» клиентов, что особенно удобно для облаков. Масштабируется все очень просто, пример HA + load balancing можно увидеть тут.

Я использую Sensu в продакшне, параллельно с Zabbix, уже около месяца, ну и в тестовом варианте пару месяцев использовал. Гибкость Sensu позволила настроить мониторинг ключевых параметров и метрик проекта с выводом на панель Dashing, в то время как Zabbix я использую уже очень давно, и занимается он сейчас более комплексным мониторингом. В общем, для многих проектов, особенно в облаках, Sensu будет прекрасным выбором, поскольку дает возможность гибко маршрутизировать события, а также хорошо приспособлен к динамической натуре облаков. В презентациях я встречал цифры в тысячи серверов под наблюдением Sensu, так что с производительностью проблем нет.

В заключение хочу указать на минусы и плюсы Sensu (все IMHO):

Минусы Sensu


  • Имеющиеся хендлеры уведомлений куцые по настройкам. Это сейчас главный минус, если вы не пользуетесь сервисами типа PagerDuty. Единственное решение — писать свой хитрый хендлер.
  • Конфиг в json, а не в yaml.
  • Нужен внешний хранитель метрик, он же рисователь графиков.
  • Не слишком полная документация. К счастью, проект простой, можно разобраться, просто читая код.


Плюсы Sensu


  • Конфиг можно хранить в git, раскладывать все с помощью Chef/Puppet.
  • Масштабируемость.
  • Отказоустойчивость.
  • Гибкость выбора системы хранения данных.
  • Поддержка плагинов Nagios.
  • Авто-подключение клиентов.
  • Механизм подписок.
  • Данные публикуются клиентами по мере генерации.
  • Результаты проверок можно гибко направлять в разные хендлеры.

+24
35.8k 200
Comments 26