Настройка Elasticsearch

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

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

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

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

Тип значения элемента данных Таблица базы данных Тип Elasticsearch
Numeric (unsigned) history_uint uint
Numeric (float) history dbl
Character history_str str
Log history_log log
Text history_text text
Binary history_bin не поддерживается Zabbix
JSON history_json json

Elasticsearch не принимает массивы JSON. Значение JSON должно быть либо одним объектом, либо набором объектов.

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

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

Если 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, какое сопоставление применять при автоматическом создании нового индекса на основе даты.
  • Создать конвейер ingest для каждого типа значения — он обрабатывает каждое входящее значение и направляет его в правильный индекс на основе даты.
Шаблоны индексов

Чтобы создать шаблон для индекса 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) задайте параметр HistoryProvider.

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

HistoryProvider=elasticsearch;value_types="str,log,text,json",url=http://localhost:9200

Если вы используете индексы на основе даты, добавьте date_index=1 к параметру:

HistoryProvider=elasticsearch;value_types="str,log,text,json",url=http://localhost:9200,date_index=1

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

systemctl restart zabbix-server

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

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

$HISTORY_PROVIDERS[] = [
  'types' => ['str','log','text','json'],
  'provider' => 'elasticsearch',
  'url' => 'http://localhost:9200'
];

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

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

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

  2. Чтобы выявить медленные запросы, используйте параметр log_slow_queries в параметре конфигурации сервера Zabbix HistoryProvider.

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

  4. Убедитесь, что 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, например:

curl 'http://localhost:9200/json/_search' \
 -H 'Content-Type: application/json' \
 -d '{
   "query": {
     "term": {
       "itemid": 42269
     }
   }
 }'
  1. Если вам нужно сбросить настройку 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/*"