Elasticsearch 设置
Zabbix 可以将历史数据存储在 Elasticsearch 中,以替代关系数据库。
本指南介绍 受支持版本 的 Elasticsearch 设置。
如果您的 Elasticsearch 版本低于支持的最低版本,Zabbix 服务器将无法启动。
如果版本高于支持的最高版本,则只有在将 AllowUnsupportedDBVersions 参数设置为 1 时,Zabbix 服务器才会启动。
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 中删除数据。 要控制数据的保留时长,请参阅 Index Lifecycle Management。
- Zabbix 不会在 Elasticsearch 中计算或存储趋势数据。 如需保留较早的数据,请考虑延长历史数据保留期。
- 使用 Elasticsearch 时,从数据库检索值的范围查询会受到数据存储期时间戳的限制。
- Elasticsearch 不支持 Zabbix proxy。
- 从 Elasticsearch 8.0 开始,默认启用安全功能:Elasticsearch 要求进行身份验证,并通过 HTTPS 使用其 HTTP API,证书由自动生成的 CA 签名。
本页中的示例使用不带身份验证的
http://localhost:9200。 如果启用了安全功能,请使用https://URL,并在请求中传递 CA 证书和凭据(例如,sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200;CA 证书文件只能由root和elasticsearch组读取)。 要将 Zabbix 服务器和 Zabbix 前端连接到此类集群,请参阅连接到安全集群。
如果尚未安装 Elasticsearch,请在继续操作前参阅官方安装指南。
配置 Elasticsearch
要将历史数据存储到 Elasticsearch 中,您需要:
- 为要存储的每种值类型创建一个 索引——这是 Elasticsearch 存储数据的位置,类似于关系型数据库中的表。
- 为每个索引定义一个 映射——它定义了数据的结构,类似于表结构。
- 设置一个 ingest pipeline,以便在存储前处理值(JSON 值和基于日期的索引必须使用)。
Elasticsearch 可以将数据存储在每种值类型对应的单个索引中,也可以分布在多个基于日期的索引中。
下面将介绍这两种方法。
将历史数据存储在单个索引中
在此方法中,给定值类型的所有历史数据都会写入单个索引(例如 uint 或 text)。
要为 Numeric (unsigned) 值类型创建索引,请向 Elasticsearch 实例发送以下请求(URL 中包含 /uint):
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 服务器配置中 value_types 选项列出的每种类型发送请求。
所有值类型的映射都可以在 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 值类型的索引会将每个值存储在以下两个字段之一中:
value_parsed—JSON 对象,以扁平化字段的形式存储,因此可以按键和值进行搜索;value_raw—所有其他 JSON 值(数组、字符串、数字、布尔值和null),以字符串形式存储。
摄取管道会将每个值解析为 JSON,并将其存储在正确的字段中。 无效的 JSON 值不会发送到 Elasticsearch,因为接收这些值的监控项会变为不受支持。
首先,创建摄取管道:
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 将返回确认信息,表明摄取管道已创建:
{"acknowledged": true}
然后,通过向 Elasticsearch 实例发送以下请求(URL 中包含 /json)来为 JSON 值类型创建索引。
default_pipeline 设置会使 Elasticsearch 使用 json 摄取管道处理写入此索引的每个值。
此设置是必需的,因为 Zabbix 服务器在将历史数据存储到单个索引时不会指定摄取管道。
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 无法为长度超过 32766 字节的 keyword 和 flattened 值创建索引。
使用 "ignore_above": 8191 后,长度超过 8191 个字符的字符串不会被索引(也无法搜索),但仍会被完整存储并返回给 Zabbix。
如果没有此限制,Elasticsearch 会拒绝此类值,并且这些值会丢失。
将历史数据存储在按日期划分的索引中
Elasticsearch 不必将所有历史数据都写入单个索引(例如 uint),而是可以将这些数据分布到多个按日期划分的索引中(例如 uint-2026-01-01、uint-2026-01-02)。
这样可以更轻松地随时间管理数据量和保留策略。
要启用此功能,您需要:
- 为要存储的每种值类型创建一个 索引模板——这会告诉 Elasticsearch 在自动创建新的按日期划分的索引时应应用哪种映射。
- 为每种值类型创建一个 ingest pipeline——它会处理每个传入的值,并将其路由到正确的按日期划分的索引。
索引模板
要为 text 索引创建模板,请发送包含以下详细信息的请求:
- 在 Elasticsearch 实例的 URL 中使用
_index_template/text_template。 - 在
"index_patterns"字段中使用"text-*",以匹配基于日期的索引名称。 - 在
"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 会拒绝索引模式与其内置模板重叠的旧版模板(例如,为 log 索引使用 log* 模式的旧版模板)。
Ingest 管道
要为 text 索引创建 ingest 管道:
- 在 Elasticsearch 实例的 URL 中使用
_ingest/pipeline/text-pipeline。 - 包含一个
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 安全功能,请指定带有凭据的 https:// URL(请参阅连接到安全集群)。
完成更改后,重启 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 安全功能,请指定与服务器配置中相同的带凭据的 https:// URL(请参阅连接到安全集群)。
连接到受保护的集群
如果启用了 Elasticsearch 安全功能(Elasticsearch 8.0 起默认启用),Zabbix 服务器和 Zabbix 前端必须信任 Elasticsearch HTTP 层的 CA 证书,并使用用户名和密码进行身份验证。
- 为 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" ]
}'
- 将 Elasticsearch CA 证书添加到 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 中的主机名必须与 Elasticsearch HTTP 证书匹配。
自动生成的证书对 localhost、主机名以及 Elasticsearch 主机的 IP 地址有效。
- 在 Zabbix 服务器配置文件和前端配置文件中,将凭据指定在 URL 中。
如果密码包含特殊字符,请对其进行百分号编码(例如,将
@编码为%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 作为 Web 服务器模块运行,则重启 Web 服务器)。
故障排除
以下步骤可能有助于排查 Elasticsearch 设置中的问题:
- 检查 Elasticsearch 或 Zabbix 服务器日志中是否存在错误。 例如,以下 Zabbix 服务器日志消息表示连接到安全集群时出现问题(请参阅连接到安全集群):
cannot query Elasticsearch: SSL certificate problem: self-signed certificate in certificate chain—Elasticsearch CA 证书不受信任;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;如果LogSlowQueries设置为 0,则每 10 秒记录一次。 -
验证 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": {} }
- 通过向相应 URL 发送
GET请求,验证映射、模板和摄取管道是否正确:
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*"
您可以将收到的响应与 Elasticsearch API 文档中的预期响应进行比较。
-
检查是否有任何分片处于失败状态;重启 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 设置并重新开始,请删除为 Zabbix 创建的索引、索引模板和摄取管道(这会删除存储在 Elasticsearch 中的所有历史数据)。
默认情况下,Elasticsearch 不允许通过通配符表达式删除索引,因此要删除基于日期的索引,请临时更改
action.destructive_requires_name设置。 索引模板和摄取管道必须逐个删除;对于不存在的模板或管道,删除请求会返回错误,可以忽略该错误。
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"