8 Настройка Elasticsearch

Zabbix может хранить исторические данные в Elasticsearch в качестве альтернативы реляционной базе данных.

Поддержка Elasticsearch в настоящее время является экспериментальной.

Это руководство описывает настройку для Elasticsearch 7.X. Если вы используете другую версию, часть функциональности может работать не так, как ожидается.

Настройка включает создание хранилища Elasticsearch для каждого типа значений, настройку предобработки (при необходимости) и подключение Zabbix к вашему экземпляру Elasticsearch.

Elasticsearch может хранить следующие типы значений:

Тип значения элемента данных Таблица базы данных Тип Elasticsearch
Числовой (без знака) history_uint uint
Числовой (с плавающей точкой) history dbl
Символьный history_str str
Журнал history_log log
Текст history_text text
Двоичный history_bin не поддерживается Zabbix
JSON history_json json

Важные примечания

  • Elasticsearch требует libcurl. Подробности см. в требованиях.
  • housekeeper не удаляет данные из Elasticsearch.
  • Если все исторические данные хранятся в Elasticsearch, тренды не вычисляются и не сохраняются в базе данных. Рассмотрите возможность увеличения периода хранения истории.
  • При использовании Elasticsearch запросы диапазона, извлекающие значения из базы данных, ограничиваются временной меткой периода хранения данных.
  • Elasticsearch не поддерживается для Zabbix прокси; вместо него используйте SQLite.

Если Elasticsearch еще не установлен, перед продолжением обратитесь к официальному руководству по установке.

Настройка Elasticsearch

Чтобы хранить исторические данные в Elasticsearch, необходимо:

  • Создать индекс для каждого типа значений, который вы хотите хранить — именно здесь Elasticsearch хранит данные, аналогично таблице в реляционной базе данных.
  • Определить mapping для каждого индекса — он задаёт структуру данных, аналогично схеме таблицы.
  • Настроить ingest pipeline для обработки значений перед сохранением (требуется для значений JSON и индексов на основе даты).

Elasticsearch может хранить данные в одном индексе для каждого типа значений или в нескольких индексах на основе даты. Оба подхода описаны ниже.

Хранение истории в одном индексе

При таком подходе все исторические данные для заданного типа значений записываются в один индекс (например, uint или text).

Чтобы создать индекс для типа значений Numeric (unsigned), отправьте следующий запрос (с /uint в URL) вашему экземпляру Elasticsearch:

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

Elasticsearch ответит подтверждением о том, что индекс был создан:

{"acknowledged": true, "shards_acknowledged": true, "index": "uint"}

Аналогичные запросы необходимо отправить для каждого дополнительного типа значений, который вы хотите хранить в Elasticsearch.

Сопоставления для всех типов значений доступны в репозитории исходного кода Zabbix.

Например, чтобы создать индекс для типа значений Text:

curl -X PUT \
 http://localhost:9200/text \
 -H 'content-type:application/json' \
 -d '{
   "settings": {
      "index": {
         "number_of_replicas": 1,
         "number_of_shards": 5
      }
   },
   "mappings": {
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "format": "epoch_second", "type": "date" },
         "value": {
            "fields": {
               "analyzed": { "index": true, "type": "text", "analyzer": "standard" }
            },
            "index": false,
            "type": "text"
         }
      }
   }
}'
Тип значения JSON

В отличие от других типов значений, значения JSON требуют дополнительной обработки перед сохранением.

Приведённый ниже индекс использует отдельные поля для разобранных и необработанных значений, поэтому для разбора каждого значения как JSON и сохранения его в правильном поле необходим ingest pipeline.

Чтобы создать индекс для типа значения JSON, отправьте следующий запрос (с /json в URL) вашему экземпляру Elasticsearch.

curl -X PUT \
 http://localhost:9200/json \
 -H 'content-type:application/json' \
 -d '{
   "settings": {
      "number_of_shards": 5,
      "number_of_replicas": 1
   },
   "mappings": {
      "dynamic": false,
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "type": "date", "format": "epoch_second" },
         "ns": { "type": "long" },
         "value_parsed": { "type": "flattened" },
         "value_raw": { "type": "keyword", "ignore_above": 1000000 }
    }
  }
}'

Затем создайте ingest pipeline:

curl -X PUT \
 http://localhost:9200/_ingest/pipeline/json \
 -H 'content-type:application/json' \
 -d '{
   "processors": [
      {
         "json": {
            "field": "value",
            "target_field": "value_parsed",
            "ignore_failure": true
         }
      },
      {
         "set": {
            "if": "ctx.value_parsed == null",
            "field": "value_raw",
            "value": "{{{ value }}}"
         }
      }
   ],
   "on_failure": [
      {
         "set": {
            "field": "value_raw",
            "value": "{{{ value }}}"
         }
      }
   ]
}'

Elasticsearch ответит подтверждением того, что ingest pipeline был создан:

{"acknowledged": true}

Хранение истории в индексах на основе даты

Вместо записи всех исторических данных в один индекс (например, uint) Elasticsearch может распределять эти данные по нескольким индексам на основе даты (например, uint-2026-01-01, uint-2026-01-02). Это упрощает управление объемом данных и сроками их хранения с течением времени.

Чтобы включить это, необходимо:

  • Создать шаблон индекса для каждого типа значения, который вы хотите хранить — это указывает Elasticsearch, какое сопоставление применять при автоматическом создании нового индекса на основе даты.
  • Создать конвейер обработки для каждого типа значения — он обрабатывает каждое входящее значение и направляет его в правильный индекс на основе даты.
  • Настроить параметр HistoryStorageDateIndex в файле конфигурации сервера Zabbix — это включает хранение значений в нескольких индексах на основе даты.
Шаблоны индексов

Чтобы создать шаблон для индекса text, отправьте запрос со следующими данными:

  • Используйте _template/text_template в URL вашего экземпляра Elasticsearch.
  • Используйте "text*" в поле "index_patterns" для сопоставления имени индекса.
  • Используйте mapping для типа значения text (см. mappings в репозитории исходного кода Zabbix).
curl -X PUT \
 http://localhost:9200/_template/text_template \
 -H 'content-type:application/json' \
 -d '{
   "index_patterns": [ "text*" ],
   "settings": {
      "index": {
         "number_of_replicas": 1,
         "number_of_shards": 5
      }
   },
   "mappings": {
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "format": "epoch_second", "type": "date" },
         "value": {
            "fields": {
               "analyzed": { "index": true, "type": "text", "analyzer": "standard" }
            },
            "index": false,
            "type": "text"
         }
      }
   }
}'

Шаблон для индекса json:

curl -X PUT \
 http://localhost:9200/_template/json_template \
 -H 'content-type:application/json' \
 -d '{
   "index_patterns": [ "json*" ],
   "settings": {
      "number_of_shards": 5,
      "number_of_replicas": 1
   },
   "mappings": {
      "dynamic": false,
      "properties": {
         "itemid": { "type": "long" },
         "clock": { "type": "date", "format": "epoch_second" },
         "ns": { "type": "long" },
         "value_parsed": { "type": "flattened" },
         "value_raw": { "type": "keyword", "ignore_above": 1000000 }
      }
   }
}'
Конвейеры ingest

Чтобы создать конвейер ingest для индекса text:

  • Используйте _ingest/pipeline/text-pipeline в URL вашего экземпляра Elasticsearch.
  • Добавьте процессор date_index_name, чтобы направлять каждое значение в правильный индекс на основе даты в соответствии с его временной меткой.
curl -X PUT \
 http://localhost:9200/_ingest/pipeline/text-pipeline \
 -H 'content-type:application/json' \
 -d '{
   "description": "daily text index naming",
   "processors": [
      {
         "date_index_name": {
            "field": "clock",
            "date_formats": ["UNIX"],
            "index_name_prefix": "text-",
            "date_rounding": "d"
         }
      }
   ]
}'

Для индекса json конвейер также должен разбирать значение JSON перед его направлением в правильный индекс:

curl -X PUT \
 http://localhost:9200/_ingest/pipeline/json-pipeline \
 -H 'content-type:application/json' \
 -d '{
   "description": "daily json index naming"
   "processors": [
      {
         "json": {
            "field": "value",
            "target_field": "value_parsed",
            "ignore_failure": true
         }
      },
      {
         "script": {
            "source": "if (ctx.value_parsed == null || !(ctx.value_parsed instanceof Map)) { ctx.value_raw = ctx.value; ctx.remove(\"value_parsed\"); }"
         }
      },
      {
         "date_index_name": {
            "field": "clock",
            "date_formats": [ "UNIX" ],
            "index_name_prefix": "json-",
            "date_rounding": "d"
         }
      }
   ]
}'

Настройка сервера Zabbix

В файле конфигурации вашего сервера Zabbix (zabbix_server.conf) задайте следующие параметры:

  • HistoryStorageURL — URL вашего экземпляра Elasticsearch.
  • HistoryStorageTypes — разделённый запятыми список типов значений для хранения в Elasticsearch.

Например, чтобы хранить в Elasticsearch значения типов Character, Log, Text и JSON (при этом сохраняя значения типа Numeric в базе данных):

HistoryStorageURL=http://localhost:9200
HistoryStorageTypes=str,log,text,json

Если вы используете индексы на основе даты для всех значений, хранящихся в Elasticsearch, также задайте параметр HistoryStorageDateIndex:

HistoryStorageDateIndex=1

После внесения изменений перезапустите сервер Zabbix:

systemctl restart zabbix-server

Настройка веб-интерфейса Zabbix

В файле конфигурации веб-интерфейса Zabbix (zabbix.conf.php) объявите $HISTORY как глобальную переменную и задайте значения url и types в соответствии с конфигурацией сервера:

// Файл конфигурации графического интерфейса Zabbix.
global $DB, $HISTORY;

$HISTORY['url']   = 'http://localhost:9200';
$HISTORY['types'] = ['str', 'log', 'text', 'json'];

Устранение неполадок

Следующие шаги могут помочь вам устранить проблемы с настройкой Elasticsearch:

  1. Убедитесь, что auto_create_index включен:
curl -X GET \
 "http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.auto_create_index"

# {"defaults": {"action": {"auto_create_index": "false"} } }

Чтобы включить его, отправьте следующий запрос:

curl -X PUT \
 http://localhost:9200/_cluster/settings \
 -H 'content-type:application/json' \
 -d '{
   "persistent": {
      "action.auto_create_index": "true"
   }
}'

# {"acknowledged": true, "persistent": {"action": {"auto_create_index": "true"} }, "transient": {} }
  1. Убедитесь, что mappings, шаблоны и ingest pipelines настроены правильно, отправив запросы GET на соответствующие URL-адреса:
curl -X GET http://localhost:9200/json
curl -X GET http://localhost:9200/_template/json*
curl -X GET http://localhost:9200/_ingest/pipeline/json*

Вы можете сравнить полученные ответы с ожидаемыми ответами в документации API Elasticsearch.

  1. Проверьте, нет ли shards в состоянии сбоя; перезапуск Elasticsearch может решить эту проблему.

  2. Убедитесь, что ваша конфигурация Elasticsearch разрешает доступ с сервера Zabbix и веб-интерфейса Zabbix.

  3. Используйте параметр конфигурации сервера Zabbix LogSlowQueries для выявления медленных запросов.

  4. Проверьте журналы Elasticsearch на наличие ошибок.

  5. Если вам нужно сбросить настройку Elasticsearch и начать заново, вы можете удалить все индексы, шаблоны и ingest pipelines:

curl -X DELETE "http://localhost:9200/_all"
curl -X DELETE "http://localhost:9200/_template/*"
curl -X DELETE "http://localhost:9200/_ingest/pipeline/*"