8 Konfiguracja Elasticsearch

Zabbix może przechowywać dane historii w Elasticsearch jako alternatywę dla relacyjnej bazy danych.

Obsługa Elasticsearch jest obecnie eksperymentalna.

Ten przewodnik opisuje konfigurację dla Elasticsearch 7.X. Jeśli używasz innej wersji, część funkcji może nie działać zgodnie z oczekiwaniami.

Konfiguracja obejmuje utworzenie lokalizacji przechowywania Elasticsearch dla każdego typu wartości, skonfigurowanie preprocessing (jeśli jest potrzebny) oraz połączenie Zabbix z instancją Elasticsearch.

Elasticsearch może przechowywać następujące typy wartości:

Typ wartości pozycji Tabela bazy danych Typ Elasticsearch
Numeryczny (unsigned) history_uint uint
Numeryczny (float) history dbl
Znakowy history_str str
Log history_log log
Tekst history_text text
Binarny history_bin nieobsługiwany przez Zabbix
JSON history_json json

Ważne uwagi

  • Elasticsearch wymaga libcurl. Szczegóły znajdują się w wymaganiach.
  • Housekeeper nie usuwa danych z Elasticsearch.
  • Jeśli wszystkie dane historii są przechowywane w Elasticsearch, trendy nie są obliczane ani przechowywane w bazie danych. Rozważ wydłużenie okresu przechowywania historii.
  • Gdy używany jest Elasticsearch, zapytania zakresowe pobierające wartości z bazy danych są ograniczone znacznikiem czasu okresu przechowywania danych.
  • Elasticsearch nie jest obsługiwany przez Zabbix proxy; zamiast tego użyj SQLite.

Jeśli Elasticsearch nie jest jeszcze zainstalowany, przed kontynuowaniem zapoznaj się z oficjalnym przewodnikiem instalacji.

Konfigurowanie Elasticsearch

Aby przechowywać dane historii w Elasticsearch, należy:

  • Utworzyć indeks dla każdego typu wartości, który chcesz przechowywać — to tutaj Elasticsearch zapisuje dane, podobnie jak tabela w relacyjnej bazie danych.
  • Zdefiniować mapowanie dla każdego indeksu — określa ono strukturę danych, podobnie jak schemat tabeli.
  • Skonfigurować pipeline przetwarzania, aby przetwarzać wartości przed zapisaniem (wymagane dla wartości JSON i indeksów opartych na dacie).

Elasticsearch może przechowywać dane w jednym indeksie dla każdego typu wartości lub w wielu indeksach opartych na dacie. Oba podejścia opisano poniżej.

Przechowywanie historii w pojedynczym indeksie

W tym podejściu wszystkie dane historii dla danego typu wartości są zapisywane w jednym indeksie (np. uint lub text).

Aby utworzyć indeks dla typu wartości Numeric (unsigned), wyślij następujące żądanie (z /uint w adresie URL) do swojej instancji 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 odpowie potwierdzeniem, że indeks został utworzony:

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

Podobne żądania należy wysłać dla każdego dodatkowego typu wartości, który chcesz przechowywać w Elasticsearch.

Mapowania dla wszystkich typów wartości są dostępne w repozytorium źródłowym Zabbix.

Na przykład, aby utworzyć indeks dla typu wartości 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"
         }
      }
   }
}'
Typ wartości JSON

W przeciwieństwie do innych typów wartości, wartości JSON wymagają dodatkowego przetwarzania przed zapisaniem.

Poniższy indeks używa oddzielnych pól dla sparsowanych i surowych wartości, dlatego do sparsowania każdej wartości jako JSON i zapisania jej w odpowiednim polu potrzebny jest ingest pipeline.

Aby utworzyć indeks dla typu wartości JSON, wyślij następujące żądanie (z /json w adresie URL) do swojej instancji 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 }
    }
  }
}'

Następnie utwórz 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 odpowie potwierdzeniem, że ingest pipeline został utworzony:

{"acknowledged": true}

Przechowywanie historii w indeksach opartych na dacie

Zamiast zapisywać wszystkie dane historii w jednym indeksie (np. uint), Elasticsearch może rozdzielać te dane pomiędzy wiele indeksów opartych na dacie (np. uint-2026-01-01, uint-2026-01-02). Ułatwia to zarządzanie ilością danych i okresem ich przechowywania w czasie.

Aby to włączyć, należy:

  • Utworzyć szablon indeksu dla każdego typu wartości, który ma być przechowywany — informuje to Elasticsearch, jakie mapowanie zastosować podczas automatycznego tworzenia nowego indeksu opartego na dacie.
  • Utworzyć pipeline ingest dla każdego typu wartości — przetwarza on każdą przychodzącą wartość i kieruje ją do właściwego indeksu opartego na dacie.
  • Skonfigurować parametr HistoryStorageDateIndex w pliku konfiguracyjnym serwera Zabbix — umożliwia to przechowywanie wartości w wielu indeksach opartych na dacie.
Szablony indeksów

Aby utworzyć szablon dla indeksu text, wyślij żądanie z następującymi szczegółami:

  • Użyj _template/text_template w adresie URL swojej instancji Elasticsearch.
  • Użyj "text*" w polu "index_patterns", aby dopasować nazwę indeksu.
  • Użyj mapowania dla typu wartości text (zobacz mapowania w repozytorium źródłowym 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"
         }
      }
   }
}'

Szablon dla indeksu 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 }
      }
   }
}'
Potoki ingest

Aby utworzyć potok ingest dla indeksu text:

  • Użyj _ingest/pipeline/text-pipeline w adresie URL swojej instancji Elasticsearch.
  • Dołącz procesor date_index_name, aby kierować każdą wartość do właściwego indeksu opartego na dacie na podstawie jej znacznika czasu.
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"
         }
      }
   ]
}'

W przypadku indeksu json potok musi również przeanalizować wartość JSON przed skierowaniem jej do właściwego indeksu:

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

Konfigurowanie serwera Zabbix

W pliku konfiguracyjnym serwera Zabbix (zabbix_server.conf) ustaw następujące parametry:

Na przykład, aby przechowywać w Elasticsearch wartości typu Character, Log, Text i JSON (przy jednoczesnym pozostawieniu wartości Numeric w bazie danych):

HistoryStorageURL=http://localhost:9200
HistoryStorageTypes=str,log,text,json

Jeśli używasz indeksów opartych na dacie dla wszystkich wartości przechowywanych w Elasticsearch, ustaw również parametr HistoryStorageDateIndex:

HistoryStorageDateIndex=1

Po wprowadzeniu zmian uruchom ponownie serwer Zabbix:

systemctl restart zabbix-server

Konfigurowanie frontendu Zabbix

W pliku konfiguracyjnym frontendu Zabbix (zabbix.conf.php) zadeklaruj $HISTORY jako zmienną globalną i ustaw wartości url oraz types tak, aby odpowiadały konfiguracji serwera:

// Zabbix GUI configuration file.
global $DB, $HISTORY;

$HISTORY['url']   = 'http://localhost:9200';
$HISTORY['types'] = ['str', 'log', 'text', 'json'];

Rozwiązywanie problemów

Poniższe kroki mogą pomóc w rozwiązywaniu problemów z konfiguracją Elasticsearch:

  1. Sprawdź, czy auto_create_index jest włączone:
curl -X GET \
 "http://localhost:9200/_cluster/settings?include_defaults=true&filter_path=**.auto_create_index"

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

Aby je włączyć, wyślij następujące żądanie:

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. Sprawdź, czy mapowania, szablony i potoki ingest są poprawne, wysyłając żądania GET do odpowiednich adresów 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*

Możesz porównać otrzymane odpowiedzi z oczekiwanymi odpowiedziami w dokumentacji API Elasticsearch.

  1. Sprawdź, czy jakiekolwiek shardy są w stanie awarii; ponowne uruchomienie Elasticsearch może rozwiązać ten problem.

  2. Sprawdź, czy konfiguracja Elasticsearch zezwala na dostęp z serwera Zabbix i frontendu Zabbix.

  3. Użyj parametru konfiguracyjnego serwera Zabbix LogSlowQueries, aby zidentyfikować wolne zapytania.

  4. Sprawdź logi Elasticsearch pod kątem błędów.

  5. Jeśli musisz zresetować konfigurację Elasticsearch i zacząć od nowa, możesz usunąć wszystkie indeksy, szablony i potoki ingest:

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