Configuração do Elasticsearch

O Zabbix pode armazenar dados de histórico em Elasticsearch como uma alternativa a um banco de dados relacional.

O suporte ao Elasticsearch atualmente é experimental.

Este guia aborda a configuração das versões suportadas do Elasticsearch. Se você estiver usando uma versão diferente, algumas funcionalidades podem não funcionar como esperado.

O Elasticsearch pode armazenar os seguintes tipos de valor:

Item value type Database table Elasticsearch type
Numeric (unsigned) history_uint uint
Numeric (float) history dbl
Character history_str str
Log history_log log
Text history_text text
Binary history_bin not supported by Zabbix
JSON history_json json

O Elasticsearch não aceita arrays JSON. Um valor JSON deve ser um único objeto ou um conjunto de objetos.

Notas importantes

  • O Elasticsearch requer libcurl. Consulte os requisitos para obter detalhes.
  • O housekeeper não exclui dados do Elasticsearch. Para controlar por quanto tempo os dados são mantidos, consulte Index Lifecycle Management.
  • O Zabbix não calcula nem armazena trends no Elasticsearch. Considere estender o período de armazenamento do histórico para preservar dados mais antigos.
  • Quando o Elasticsearch é usado, as consultas de intervalo que recuperam valores do banco de dados são limitadas pelo timestamp do período de armazenamento dos dados.
  • O Elasticsearch não é suportado para proxies do Zabbix.

Se o Elasticsearch ainda não estiver instalado, consulte o guia oficial de instalação antes de prosseguir.

Configurando o Elasticsearch

Para armazenar dados históricos no Elasticsearch, você precisa:

  • Criar um índice para cada tipo de valor que deseja armazenar—é aqui que o Elasticsearch armazena os dados, semelhante a uma tabela em um banco de dados relacional.
  • Definir um mapeamento para cada índice—isso define a estrutura dos dados, semelhante ao esquema de uma tabela.
  • Configurar um pipeline de ingestão para processar valores antes do armazenamento (necessário para valores JSON e índices baseados em data).

O Elasticsearch pode armazenar dados em um único índice por tipo de valor ou em vários índices baseados em data. Ambas as abordagens são descritas abaixo.

Armazenando histórico em um único índice

Nesta abordagem, todos os dados de histórico para um determinado tipo de valor são gravados em um único índice (por exemplo, uint ou text).

Para criar um índice para o tipo de valor Numérico (sem sinal), envie a seguinte solicitação (com /uint na URL) para sua instância do 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" }
      }
   }
}'

O Elasticsearch responderá com uma confirmação de que o índice foi criado:

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

Solicitações semelhantes devem ser enviadas para cada tipo de valor adicional que você deseja armazenar no Elasticsearch.

Os mapeamentos para todos os tipos de valor estão disponíveis no repositório de código-fonte do Zabbix.

Por exemplo, para criar um índice para o tipo de valor Texto:

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"
         }
      }
   }
}'
Tipo de valor JSON

Ao contrário de outros tipos de valor, os valores JSON requerem processamento adicional antes do armazenamento.

O índice abaixo utiliza campos separados para valores analisados e brutos, portanto, um ingest pipeline é necessário para analisar cada valor como JSON e armazená-lo no campo correto.

Para criar um índice para o tipo de valor JSON, envie a seguinte solicitação (com /json na URL) para sua instância do 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 }
    }
  }
}'

Em seguida, crie o 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 }}}"
         }
      }
   ]
}'

O Elasticsearch responderá com uma confirmação de que o ingest pipeline foi criado:

{"acknowledged": true}

Armazenando o histórico em índices baseados em data

Em vez de gravar todos os dados de histórico em um único índice (por exemplo, uint), o Elasticsearch pode distribuir esses dados entre vários índices baseados em data (por exemplo, uint-2026-01-01, uint-2026-01-02). Isso facilita o gerenciamento do volume de dados e da retenção ao longo do tempo.

Para habilitar isso, você precisa:

  • Criar um index template para cada tipo de valor que deseja armazenar — isso informa ao Elasticsearch qual mapeamento aplicar quando ele criar automaticamente um novo índice baseado em data.
  • Criar um ingest pipeline para cada tipo de valor — ele processa cada valor recebido e o encaminha para o índice baseado em data correto.
Indexar templates

Para criar um template para o índice text, envie uma solicitação com os seguintes detalhes:

  • Use _template/text_template na URL da sua instância do Elasticsearch.
  • Use "text*" no campo "index_patterns" para corresponder ao nome do índice.
  • Use um mapeamento para o tipo de valor text (veja os mapeamentos no repositório fonte do 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"
         }
      }
   }
}'

Template para o índice 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 }
      }
   }
}'
Pipelines de ingestão

Para criar um pipeline de ingestão para o índice text:

  • Use _ingest/pipeline/text-pipeline na URL da sua instância do Elasticsearch.
  • Inclua um processador date_index_name para direcionar cada valor para o índice baseado em data correto com base em seu timestamp.
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"
         }
      }
   ]
}'

Para o índice json, o pipeline também precisa analisar o valor JSON antes de direcioná-lo para o índice correto:

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

Configurando o Zabbix server

No arquivo de configuração do seu Zabbix server (zabbix_server.conf), defina o parâmetro HistoryProvider.

Por exemplo, para armazenar valores dos tipos Character, Log, Text e JSON no Elasticsearch (mantendo os valores Numeric em um banco de dados):

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

Se você estiver usando índices baseados em data, adicione date_index=1 ao parâmetro:

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

Após fazer as alterações, reinicie o Zabbix server:

systemctl restart zabbix-server

Configurando o frontend do Zabbix

No arquivo de configuração do seu frontend do Zabbix (zabbix.conf.php), defina a variável $HISTORY_PROVIDERS para corresponder à configuração do server:

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

Solução de problemas

As etapas a seguir podem ajudar você a solucionar problemas com sua configuração do Elasticsearch:

  1. Verifique os logs do Elasticsearch ou do server do Zabbix em busca de erros.

  2. Para identificar consultas lentas, use a opção log_slow_queries no parâmetro de configuração do server do Zabbix HistoryProvider.

  3. Verifique se o Elasticsearch permite acesso a partir do server do Zabbix e do frontend do Zabbix.

  4. Verifique se auto_create_index está habilitado:

curl -X GET \
 "http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.auto_create_index"

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

Para habilitá-lo, envie a seguinte solicitação:

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. Verifique se os mappings, templates e ingest pipelines estão corretos enviando solicitações GET para suas respectivas URLs:
curl -X GET http://localhost:9200/json
curl -X GET http://localhost:9200/_template/json*
curl -X GET http://localhost:9200/_ingest/pipeline/json*

Você pode comparar as respostas recebidas com as respostas esperadas na documentação da API do Elasticsearch.

  1. Verifique se há algum shard em estado de falha; reiniciar o Elasticsearch pode resolver isso.

  2. Consulte o Elasticsearch para ver se os dados coletados pelo Zabbix estão armazenados, por exemplo:

curl 'http://localhost:9200/json/_search' \
 -H 'Content-Type: application/json' \
 -d '{
   "query": {
     "term": {
       "itemid": 42269
     }
   }
 }'
  1. Se você precisar redefinir sua configuração do Elasticsearch e começar do zero, poderá excluir todos os índices, templates e ingest pipelines:
curl -X DELETE "http://localhost:9200/_all"
curl -X DELETE "http://localhost:9200/_template/*"
curl -X DELETE "http://localhost:9200/_ingest/pipeline/*"