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 时,从数据库中检索值的范围查询会受到数据存储期时间戳的限制。
  • Zabbix proxy 不支持 Elasticsearch;请改用 SQLite。

如果尚未安装 Elasticsearch,请先参阅官方安装指南后再继续。

配置 Elasticsearch

要将历史数据存储到 Elasticsearch 中,您需要:

  • 为要存储的每种值类型创建一个 索引——这是 Elasticsearch 存储数据的位置,类似于关系型数据库中的表。
  • 为每个索引定义一个 映射——它定义了数据的结构,类似于表结构。
  • 设置一个 ingest pipeline,以便在存储前处理值(JSON 值和基于日期的索引必须使用)。

Elasticsearch 可以将数据存储在每种值类型对应的单个索引中,也可以分布在多个基于日期的索引中。
下面将介绍这两种方法。

将历史数据存储在单个索引中

在这种方法中,给定值类型的所有历史数据都会写入单个索引(例如 uinttext)。

要为 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 源代码仓库 中找到。

例如,要为 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 值在存储前需要额外处理。

下面的索引对已解析值和原始值使用了单独的字段,因此需要使用 ingest pipeline 将每个值解析为 JSON 并存储到正确的字段中。

要为 JSON 值类型创建索引,请向您的 Elasticsearch 实例发送以下请求(URL 中包含 /json)。

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}

在基于日期的索引中存储历史数据

Elasticsearch 不必将所有历史数据写入单个索引中(例如 uint),而是可以将这些数据分布到多个基于日期的索引中(例如 uint-2026-01-01uint-2026-01-02)。 这样可以更轻松地管理随时间增长的数据量和数据保留。

要启用此功能,您需要:

  • 为要存储的每种值类型创建一个索引模板——这会告知 Elasticsearch 在其自动创建新的基于日期的索引时应应用什么映射。
  • 为每种值类型创建一个摄取管道——它会处理每个传入的值,并将其路由到正确的基于日期的索引。
  • 在 Zabbix 服务器配置文件中配置 HistoryStorageDateIndex 参数——这将启用在多个基于日期的索引中存储值。
索引模板

要为 text 索引创建模板,请发送包含以下详细信息的请求:

  • 在 Elasticsearch 实例的 URL 中使用 _template/text_template
  • "index_patterns" 字段中使用 "text*" 以匹配索引名称。
  • text 值类型使用映射(请参见 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 pipeline

要为 text 索引创建 ingest pipeline:

  • 在 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"
         }
      }
   ]
}'

对于 json 索引,该 pipeline 还需要先解析 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)中,设置以下参数:

例如,要将 CharacterLogTextJSON 类型的值存储到 Elasticsearch 中(同时将 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 声明为全局变量,并设置其 urltypes 值,使其与服务器配置匹配:

// Zabbix GUI configuration file.
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. 通过向各自的 URL 发送 GET 请求,验证映射、模板和摄取管道是否正确:
curl -X GET http://localhost:9200/json
curl -X GET http://localhost:9200/_template/json*
curl -X GET http://localhost:9200/_ingest/pipeline/json*

您可以将收到的响应与 Elasticsearch API 文档中的预期响应进行比较。

  1. 检查是否有任何 分片处于失败状态;重启 Elasticsearch 可能会解决此问题。

  2. 验证您的 Elasticsearch 配置是否允许来自 Zabbix 服务器和 Zabbix 前端的访问。

  3. 使用 LogSlowQueries Zabbix 服务器配置参数来识别慢查询。

  4. 检查 Elasticsearch 日志中是否有错误。

  5. 如果您需要重置 Elasticsearch 设置并重新开始,可以删除所有索引、模板和摄取管道:

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