Konfiguracja Elasticsearch

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

Obsługa Elasticsearch jest obecnie eksperymentalna.

Ten przewodnik obejmuje konfigurację obsługiwanych wersji Elasticsearch. Jeśli używasz innej wersji, niektóre funkcje mogą nie działać zgodnie z oczekiwaniami.

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

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

Elasticsearch nie akceptuje tablic JSON. Wartość JSON musi być pojedynczym obiektem albo zbiorem obiektów.

Ważne uwagi

  • Elasticsearch wymaga libcurl. Szczegóły znajdują się w sekcji wymagania.
  • housekeeper nie usuwa danych z Elasticsearch. Aby kontrolować, jak długo dane są przechowywane, zobacz Index Lifecycle Management.
  • Zabbix nie oblicza ani nie przechowuje trendów w Elasticsearch. Rozważ wydłużenie okresu przechowywania historii, aby zachować starsze dane.
  • Gdy używany jest Elasticsearch, zapytania zakresowe pobierające wartości z bazy danych są ograniczone przez znacznik czasu okresu przechowywania danych.
  • Elasticsearch nie jest obsługiwany dla proxy Zabbix.

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 historyczne do jednego indeksu (np. uint), Elasticsearch może rozdzielać te dane między wiele indeksów opartych na dacie (np. uint-2026-01-01, uint-2026-01-02). Ułatwia to zarządzanie wolumenem danych oraz ich retencją w czasie.

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

  • Utworzyć szablon indeksu dla każdego typu wartości, który chcesz przechowywać — 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.
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 parametr HistoryProvider.

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

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

Jeśli używasz indeksów opartych na dacie, dodaj date_index=1 do parametru:

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

Po wprowadzeniu zmian uruchom ponownie serwer Zabbix:

systemctl restart zabbix-server

Konfigurowanie frontend Zabbix

W pliku konfiguracyjnym frontend Zabbix (zabbix.conf.php) ustaw zmienną $HISTORY_PROVIDERS, aby odpowiadała konfiguracji serwera:

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

Rozwiązywanie problemów

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

  1. Sprawdź dzienniki Elasticsearch lub serwera Zabbix pod kątem błędów.

  2. Aby zidentyfikować wolne zapytania, użyj opcji log_slow_queries w parametrze konfiguracji serwera Zabbix HistoryProvider.

  3. Sprawdź, czy Elasticsearch zezwala na dostęp z serwera Zabbix i frontend Zabbix.

  4. 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 ich 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*

Otrzymane odpowiedzi możesz porównać z oczekiwanymi odpowiedziami w dokumentacji API Elasticsearch.

  1. Sprawdź, czy jakiekolwiek shardy nie znajdują się w stanie awarii; ponowne uruchomienie Elasticsearch może to rozwiązać.

  2. Wykonaj zapytanie do Elasticsearch, aby sprawdzić, czy dane zebrane przez Zabbix są przechowywane, na przykład:

curl 'http://localhost:9200/json/_search' \
 -H 'Content-Type: application/json' \
 -d '{
   "query": {
     "term": {
       "itemid": 42269
     }
   }
 }'
  1. 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/*"