СоХабр закрыт.

С 13 мая 2019 года он не сканирует новые посты.
С 20 мая 2019 года не перенесённые в черновики посты теперь редиректят на Хабр.

| сохранено

H Хранение истории Zabbix в elasticsearch в черновиках Из песочницы

Привет всем!

Давно использую систему мониторинга zabbix (исторически так сложилось), и в плане использования меня всё устраивает, а вот в плане архитектуры не очень.

Что меня не устраивает в архитектуре zabbix:

  1. Текущая ситуация с хранением исторических данных в реляционной БД. Занимает много места, плохо чистится (кроме случая с partitioning), да и сам подход хранения данных, для которых не используются внешние ключи, в реляционной БД — «такое себе»
  2. В grafana тянуть данные через запросы из БД через api zabbix (напрямую из БД неудобно по причине сопоставления itemid). Излишняя нагрузка на всю СУБД, производительность. В моём случае это важно, любит бизнес посмотреть на красивые графики, а ещё любит строить их за большой период. (чего уж таить, и сам этим грешу)
  3. Масштабируемость СУБД. Нет, кластер реляционной БД не предлагать (по первым двум причинам).

Давно мечтал о возможности хранения исторических данных в нереляционной БД, но вот беда, zabbix из коробки этого не умеет, а времени на «допиливание» и/или бюджета — нет. А ведь так хочется отделить исторические данные от всего остального (триггеров, действий, оповещений и прочего). Да и если есть стек ELK, то уже и кластер elasticsearch готов. Знакомо? Так вот, с версии 3.4.5 zabbix эксперементально поддерживает хранение исторических данных в elasticsearch. А значит наша архитектура может выглядеть так:



В документации zabbix описано следующее:



То есть любые действия мы делаем на свой страх и риск.

И так, первое что я сделал, развернул чистый zabbix и elastic.

Далее поправил конфиг согласно документации.
vi /etc/zabbix/zabbix_server.conf

### Option: HistoryStorageURL
#       History storage HTTP[S] URL.
#
# Mandatory: no
# Default:
# HistoryStorageURL=
HistoryStorageURL=http://hostnameelastic:9200

### Option: HistoryStorageTypes
#       Comma separated list of value types to be sent to the history storage.
#
# Mandatory: no
# Default:
# HistoryStorageTypes=uint,dbl,str,log,text
HistoryStorageTypes=uint,dbl,str,log,text

vi /etc/zabbix/web/zabbix.conf.php
<?php
// Zabbix GUI configuration file.

global $DB, $HISTORY;
$DB['TYPE']     = 'MYSQL';
$DB['SERVER']   = 'zabbixDB';
$DB['PORT']     = '3306';
$DB['DATABASE'] = 'zabbix';
$DB['USER']     = 'zabbix';
$DB['PASSWORD'] = 'zabbix';

// Schema name. Used for IBM DB2 and PostgreSQL.
$DB['SCHEMA'] = '';

$ZBX_SERVER      = 'localhost';
$ZBX_SERVER_PORT = '10051';
$ZBX_SERVER_NAME = '';

$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;

$HISTORY['url']   = [
        'uint' => 'http://hostnameelastic:9200',
        'text' => 'http://hostnameelastic:9200',
        'str' => 'http://hostnameelastic:9200',
        'log' => 'http://hostnameelastic:9200',
        'dbl' => 'http://hostnameelastic:9200'
];
$HISTORY['types'] = ['uint', 'text', 'str', 'log', 'dbl'];


На этом настройка zabbix сервера закончена и начинается настройка elasticsearch.

Создаём индексы для типов данных, которые указали в настройках zabbix:

пример
Для типа uint:

curl -X PUT \
 http://hostnameelastic:9200/uint \
 -H 'content-type:application/json' \
 -d '{
   "settings" : {
      "index" : {
         "number_of_replicas" : 1,
         "number_of_shards" : 5
      }
   },
   "mappings" : {
      "values" : {
         "properties" : {
            "itemid" : {
               "type" : "long"
            },
            "clock" : {
               "format" : "epoch_second",
               "type" : "date"
            },
            "value" : {
               "type" : "long"
            }
         }
      }
   }
}'

Для типа dbl:

curl -X PUT \
 http://hostnameelastic:9200/dbl \
 -H 'content-type:application/json' \
 -d '{
   "settings" : {
      "index" : {
         "number_of_replicas" : 1,
         "number_of_shards" : 5
      }
   },
   "mappings" : {
      "values" : {
         "properties" : {
            "itemid" : {
               "type" : "long"
            },
            "clock" : {
               "format" : "epoch_second",
               "type" : "date"
            },
            "value" : {
               "type" : "double"
            }
         }
      }
   }
}'

Аналогично для типов text,str,log.

Запускаем zabbix сервер и наблюдаем, как поступают данные.

На этом всё, zabbix пишет в elasticsearch, оттуда же забирает данные для отображения. Одно но, не буду же я сносить уже рабочий сервер zabbix с потерей всех данных… Нужно как-то мигрировать… Нам на помощь приходит logstash и плагин jdbc. Установку описывать не стану только конфигурационные файлы для pipeline.

клик
Для типа uint:
input {
  jdbc {
    jdbc_connection_string => "jdbc:mysql://hostnameDBzabbix:3306/DBzabbixname"
    # Пользователь, под которым есть доступ в БД (хотя бы на чтение)
    jdbc_user => "userdb"
    jdbc_password => "passdb"
    # Путь к jdbc драйверу (нужно предварительно скачать)
    jdbc_driver_library => "path-to-mysql-connector-java-5.1.46/mysql-connector-java-5.1.46.jar"
    jdbc_driver_class => "com.mysql.jdbc.Driver"
    #Следующие две строки запрашивают данные "постранично".
    jdbc_paging_enabled => true
    jdbc_page_size => 200000
    # Строка запроса
    statement => "SELECT * FROM history_uint"
    }
  }
output {
  stdout { codec => json_lines }
  elasticsearch {
  "hosts" => "elastichostname:9200"
# Указываем индекс, в который будут отправляться данные
   "index" => "uint"
# Вот тут я долго не мог понять какой именно тип document_type указывать.... В итоге заработало с "values", но окончательного понимания так и не пришло. Если есть знатоки elastic-а, прошу пояснить в комментариях. Спасибо.
  "document_type" => "values"
    "manage_template" => "true"

  }
}

Аналогично для остальных типов. Важно! Не указывайте в запросе несколько таблиц, у них разные типы данных! Т.е. правим конфигурационный файл под каждый тип данных. Logstash можно не перезапускать при этом, после остановки pipeline он перечитает конфигурационные файлы.

Данные мигрировали, всё здорово, всё отображается… Пришло время удалить старые данные…

клик
Пример запроса:
curl -vv -XPOST 'http://hostnameelastic:9200/uint*/_delete_by_query' \
 -H 'content-type:application/json' \
-d '{
    "query": {
        "range" : {
            "clock" : {
                "gte" : "1528848001",
                "lte" :  "1528930801"
            }
        }
    }
}'

Где «gte» — начиная с указанной даты включительно. «lte» — по указанную дату включительно.
Также есть «gt» — тоже что и «gte», но без включительно, «lt» — тоже что и «lte», но без включительно.

Значение в unix timestamp. Есть онлайн ресурс с конвертацией. У меня не получилось задать дату в читаемом виде, т.к. в индекс она записывается в unix timestamp.

На данный момент я тестово мигрирую данные объём ~100 Гб. Процесс очень долгий, так как система мониторинга критична и очень не хочется оказывать негативного влияния. По окончании я напишу «UPD» о том, как это происходило, как соблюдалась консистентность данных и сколько это заняло времени.

P.S.
У меня опыта работы с elasticsearch минимально. Многие вещи для меня и сейчас остаются загадкой. Если будут комментарии о том как сделать лучше — я буду очень рад. Да, документацию много раз читал — нет, не помогает, особенно в части type, _type, document type и изменений с 6.х

комментарии (0)