Настройка Elasticsearch
Zabbix может хранить данные истории в Elasticsearch в качестве альтернативы реляционной базе данных.
В этом руководстве описана настройка поддерживаемых версий Elasticsearch.
Сервер Zabbix не запускается, если ваша версия Elasticsearch старше минимальной поддерживаемой версии.
Если она новее максимальной поддерживаемой версии, сервер Zabbix запускается только в том случае, если параметр AllowUnsupportedDBVersions установлен в значение 1.
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. Подробнее см. в разделе требования.
- Сборщик мусора не удаляет данные из Elasticsearch. Чтобы управлять сроком хранения данных, см. раздел управление жизненным циклом индексов.
- Zabbix не вычисляет и не хранит тренды в Elasticsearch. Чтобы сохранить более старые данные, рассмотрите возможность увеличения периода хранения истории.
- При использовании Elasticsearch диапазонные запросы, извлекающие значения из базы данных, ограничены временной меткой периода хранения данных.
- Elasticsearch не поддерживается для прокси Zabbix.
- Начиная с Elasticsearch 8.0 функции безопасности включены по умолчанию: Elasticsearch требует аутентификацию и использует HTTPS для своего HTTP API, а сертификаты подписываются автоматически сгенерированным центром сертификации.
В примерах на этой странице используется
http://localhost:9200без аутентификации. Если безопасность включена, используйте URLhttps://и передавайте в запросах сертификат центра сертификации и учетные данные (например,sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200; файл сертификата центра сертификации может быть прочитан только пользователемrootи группойelasticsearch). Чтобы подключить сервер Zabbix и веб-интерфейс Zabbix к такому кластеру, см. раздел Подключение к защищенному кластеру.
Если Elasticsearch еще не установлен, перед продолжением ознакомьтесь с официальным руководством по установке.
Настройка Elasticsearch
Чтобы хранить исторические данные в Elasticsearch, необходимо:
- Создать индекс для каждого типа значений, который вы хотите хранить — именно здесь Elasticsearch хранит данные, аналогично таблице в реляционной базе данных.
- Определить mapping для каждого индекса — он задаёт структуру данных, аналогично схеме таблицы.
- Настроить ingest pipeline для обработки значений перед сохранением (требуется для значений JSON и индексов на основе даты).
Elasticsearch может хранить данные в одном индексе для каждого типа значений или в нескольких индексах на основе даты. Оба подхода описаны ниже.
Хранение истории в одном индексе
В этом подходе все данные истории для заданного типа значения записываются в один индекс (например, uint или text).
Чтобы создать индекс для типа значения Числовой (без знака), отправьте следующий запрос (с /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, то есть для каждого типа, указанного в параметре value_types конфигурации сервера Zabbix.
Сопоставления для всех типов значений доступны в репозитории исходного кода Zabbix.
Например, чтобы создать индекс для типа значения Текст:
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 хранит каждое значение в одном из двух полей:
value_parsed— объекты JSON, хранящиеся как поле flattened, чтобы их можно было искать по ключу и значению;value_raw— все остальные значения JSON (массивы, строки, числа, логические значения иnull), хранящиеся в виде строки.
Конвейер ingest анализирует каждое значение как JSON и сохраняет его в соответствующем поле. Значения, не являющиеся допустимым JSON, не отправляются в Elasticsearch, поскольку элементы данных, которые их получают, становятся неподдерживаемыми.
Сначала создайте конвейер ingest:
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
}
},
{
"script": {
"source": "if (ctx.value_parsed == null || !(ctx.value_parsed instanceof Map)) { ctx.value_raw = ctx.value; ctx.remove(\"value_parsed\"); }"
}
}
]
}'
Elasticsearch ответит подтверждением создания конвейера ingest:
{"acknowledged": true}
Затем создайте индекс для типа значения JSON, отправив следующий запрос к вашему экземпляру Elasticsearch (обратите внимание на /json в URL).
Параметр default_pipeline заставляет Elasticsearch обрабатывать каждое значение, записываемое в этот индекс, с помощью конвейера ingest json.
Этот параметр необходим, поскольку сервер Zabbix не указывает конвейер ingest при сохранении истории в одном индексе.
curl -X PUT \
http://localhost:9200/json \
-H 'content-type:application/json' \
-d '{
"settings": {
"index": {
"number_of_replicas": 1,
"number_of_shards": 5,
"default_pipeline": "json"
}
},
"mappings": {
"dynamic": false,
"properties": {
"itemid": { "type": "long" },
"clock": { "type": "date", "format": "epoch_second" },
"ns": { "type": "long" },
"value_parsed": { "type": "flattened", "ignore_above": 8191 },
"value_raw": { "type": "keyword", "ignore_above": 8191 }
}
}
}'
Elasticsearch не может индексировать значения keyword и flattened длиной более 32766 байт.
При использовании "ignore_above": 8191 строки длиной более 8191 символа не индексируются (и не могут использоваться для поиска), но по-прежнему сохраняются и возвращаются узлу сети Zabbix полностью.
Без этого ограничения Elasticsearch отклоняет такие значения, и они теряются.
Хранение истории в индексах на основе даты
Вместо записи всех данных истории в один индекс (например, uint) Elasticsearch может распределять эти данные по нескольким индексам на основе даты (например, uint-2026-01-01, uint-2026-01-02).
Это упрощает управление объемом данных и сроками хранения с течением времени.
Чтобы включить это, необходимо:
- Создать шаблон индекса для каждого типа значения, который вы хотите хранить — это сообщает Elasticsearch, какое сопоставление применять при автоматическом создании нового индекса на основе даты.
- Создать конвейер ingest для каждого типа значения — он обрабатывает каждое входящее значение и направляет его в правильный индекс на основе даты.
Шаблоны индексов
Чтобы создать шаблон для индекса text, отправьте запрос со следующими параметрами:
- Используйте
_index_template/text_templateв URL вашего экземпляра Elasticsearch. - Используйте
"text-*"в поле"index_patterns", чтобы сопоставить имена индексов на основе дат. - В поле
"template"укажите настройки индекса и сопоставление для типа значенияtext(см. сопоставления в репозитории исходного кода Zabbix).
curl -X PUT \
http://localhost:9200/_index_template/text_template \
-H 'content-type:application/json' \
-d '{
"index_patterns": [ "text-*" ],
"template": {
"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 (подробные сведения о полях value_parsed и value_raw см. в разделе Тип значения JSON):
curl -X PUT \
http://localhost:9200/_index_template/json_template \
-H 'content-type:application/json' \
-d '{
"index_patterns": [ "json-*" ],
"template": {
"settings": {
"number_of_replicas": 1
},
"mappings": {
"dynamic": false,
"properties": {
"itemid": { "type": "long" },
"clock": { "type": "date", "format": "epoch_second" },
"ns": { "type": "long" },
"value_parsed": { "type": "flattened", "ignore_above": 8191 },
"value_raw": { "type": "keyword", "ignore_above": 8191 }
}
}
}
}'
Используйте составные шаблоны индексов (_index_template), как показано выше.
Устаревшие шаблоны индексов (_template) не рекомендуются к использованию, и Elasticsearch отклоняет устаревшие шаблоны, шаблоны индексов которых пересекаются со встроенными шаблонами Elasticsearch (например, устаревший шаблон с шаблоном log* для индекса log).
Конвейеры 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"
}
}
]
}'
Создайте конвейер для каждого типа значения, которое вы хотите хранить, изменив имя конвейера, описание и значение "index_name_prefix" соответствующим образом.
Имя конвейера должно состоять из имени индекса и суффикса -pipeline (например, uint-pipeline), поскольку сервер Zabbix использует это имя при отправке значений в Elasticsearch.
Для индекса 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
Если включены функции безопасности Elasticsearch, укажите URL https:// с учетными данными (см. раздел Подключение к защищенному кластеру).
После внесения изменений перезапустите сервер 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 включены, укажите тот же URL https:// с учетными данными, что и в конфигурации сервера (см. раздел Подключение к защищенному кластеру).
Подключение к защищенному кластеру
Если функции безопасности Elasticsearch включены (по умолчанию начиная с Elasticsearch 8.0), сервер Zabbix и веб-интерфейс Zabbix должны доверять сертификату CA HTTP-уровня Elasticsearch и проходить аутентификацию с использованием имени пользователя и пароля.
- Создайте роль и пользователя для Zabbix.
Следующая роль позволяет Zabbix получать версию Elasticsearch (привилегия кластера
monitor), создавать индексы, записывать и читать данные истории, а также удалять данные истории при очистке истории элемента данных:
sudo curl -X PUT \
--cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
https://localhost:9200/_security/role/zabbix_history \
-H 'content-type:application/json' \
-d '{
"cluster": [ "monitor" ],
"indices": [
{
"names": [ "uint", "uint-*", "dbl", "dbl-*", "str", "str-*", "log", "log-*", "text", "text-*", "json", "json-*" ],
"privileges": [ "create_index", "index", "read", "delete" ]
}
]
}'
sudo curl -X PUT \
--cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
https://localhost:9200/_security/user/zabbix \
-H 'content-type:application/json' \
-d '{
"password": "<password>",
"roles": [ "zabbix_history" ]
}'
- Добавьте сертификат CA Elasticsearch в список доверенных сертификатов операционной системы на узлах сети сервера Zabbix и веб-интерфейса Zabbix.
Если Zabbix работает на другом узле сети, отличном от Elasticsearch, сначала скопируйте сертификат CA (
/etc/elasticsearch/certs/http_ca.crt) на этот узел сети. Например, в Debian/Ubuntu:
sudo cp /etc/elasticsearch/certs/http_ca.crt /usr/local/share/ca-certificates/elasticsearch-http-ca.crt
sudo update-ca-certificates
Имя узла сети в URL должно совпадать с именем в HTTP-сертификате Elasticsearch.
Автоматически созданный сертификат действителен для localhost, имени узла сети и IP-адресов узла сети Elasticsearch.
- Укажите учетные данные в URL как в файле конфигурации сервера Zabbix, так и в файле конфигурации веб-интерфейса.
Если пароль содержит специальные символы, закодируйте их в формате percent-encoding (например,
@как%40,:как%3A, а,как%2C).
HistoryProvider=elasticsearch;value_types="str,log,text,json",url=https://zabbix:<password>@localhost:9200
$HISTORY_PROVIDERS[] = [
'types' => ['str','log','text','json'],
'provider' => 'elasticsearch',
'url' => 'https://zabbix:<password>@localhost:9200'
];
- Перезапустите сервер Zabbix и PHP-FPM (или веб-сервер, если PHP работает как модуль веб-сервера).
Устранение неполадок
Следующие действия могут помочь устранить проблемы с настройкой Elasticsearch:
- Проверьте журналы Elasticsearch или сервера Zabbix на наличие ошибок. Например, следующие сообщения в журнале сервера Zabbix указывают на проблемы с подключением к защищенному кластеру (см. раздел Подключение к защищенному кластеру):
cannot query Elasticsearch: SSL certificate problem: self-signed certificate in certificate chain— сертификат CA Elasticsearch не является доверенным;cannot query Elasticsearch, HTTP error message: The requested URL returned error: 401— учетные данные отсутствуют или указаны неправильно;cannot query Elasticsearch, HTTP error message: The requested URL returned error: 403— у пользователя нет необходимых привилегий.
В веб-интерфейсе Zabbix отображаются аналогичные ошибки (например, Elasticsearch error: missing authentication credentials for REST request).
-
Чтобы выявить медленные запросы, задайте параметр конфигурации сервера Zabbix
LogSlowQueries. Если чтение истории из Elasticsearch занимает больше указанного времени, сервер Zabbix записывает в журнал сообщениеslow query: <N> sec, "<query>". Во время ожидания ответа Elasticsearch сервер Zabbix также записывает сообщениеwaiting for Elasticsearch response <N>secкаждый раз по истечении указанного времени или каждые 10 секунд, если дляLogSlowQueriesзадано значение 0. -
Убедитесь, что Elasticsearch разрешает доступ с сервера Zabbix и из веб-интерфейса Zabbix.
-
Убедитесь, что параметр
auto_create_indexвключен (по умолчанию он включен):
curl -X GET \
"http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.auto_create_index"
# {"persistent": {"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": {} }
- Проверьте правильность mappings, шаблонов и ingest pipelines, отправив запросы
GETк соответствующим URL:
curl -X GET "http://localhost:9200/json*"
curl -X GET "http://localhost:9200/_index_template/json*"
curl -X GET "http://localhost:9200/_ingest/pipeline/json*"
Полученные ответы можно сравнить с ожидаемыми ответами в документации по API Elasticsearch.
-
Проверьте, не находятся ли какие-либо шарды в состоянии сбоя; перезапуск Elasticsearch может решить эту проблему. В одновузловом кластере индексы с репликами (
"number_of_replicas": 1) имеют желтый статус, поскольку реплики нельзя разместить на том же узле, что и первичные шарды; это не влияет на Zabbix. Чтобы избежать этого, задайте для"number_of_replicas"значение0. -
Выполните запрос к Elasticsearch, чтобы проверить, сохранены ли собранные Zabbix данные, например:
curl "http://localhost:9200/json*/_search" \
-H 'Content-Type: application/json' \
-d '{
"query": {
"term": {
"itemid": 42269
}
}
}'
- Если необходимо сбросить настройку Elasticsearch и начать заново, удалите индексы, шаблоны индексов и ingest pipelines, созданные для Zabbix (при этом удаляются все данные истории, хранящиеся в Elasticsearch).
По умолчанию Elasticsearch не разрешает удалять индексы с помощью выражений с подстановочными знаками, поэтому для удаления индексов на основе дат временно измените параметр
action.destructive_requires_name. Шаблоны индексов и ingest pipelines необходимо удалять по одному; запросы к несуществующим шаблонам или pipelines возвращают ошибку, которую можно игнорировать.
curl -X DELETE "http://localhost:9200/uint,dbl,str,log,text,json?ignore_unavailable=true"
curl -X PUT \
http://localhost:9200/_cluster/settings \
-H 'content-type:application/json' \
-d '{"persistent": {"action.destructive_requires_name": false}}'
curl -X DELETE "http://localhost:9200/uint-*,dbl-*,str-*,log-*,text-*,json-*"
curl -X PUT \
http://localhost:9200/_cluster/settings \
-H 'content-type:application/json' \
-d '{"persistent": {"action.destructive_requires_name": null}}'
for type in uint dbl str log text json; do
curl -X DELETE "http://localhost:9200/_index_template/${type}_template"
curl -X DELETE "http://localhost:9200/_ingest/pipeline/${type}-pipeline"
done
curl -X DELETE "http://localhost:9200/_ingest/pipeline/json"