ProHoster > Blog > Uprava > Dolgoročno shranjevanje podatkov v Elasticsearch
Dolgoročno shranjevanje podatkov v Elasticsearch
Moje ime je Igor Sidorenko, sem tehnični vodja v ekipi administratorjev, ki vzdržujejo celotno infrastrukturo Domklika v brezhibnem stanju.
Rad bi delil svojo izkušnjo pri nastavitvi porazdeljenega shranjevanja podatkov v Elasticsearch. Ogledali si bomo, katere nastavitve na vozliščih so odgovorne za porazdelitev drobcev, kako je ILM strukturiran in deluje.
Tisti, ki tako ali drugače delajo s hlodi, se soočajo s problemom dolgotrajnega shranjevanja za naknadno analizo. To še posebej velja za Elasticsearch, ker je bila funkcija kuratorja slaba. V različici 6.6 se je pojavila funkcionalnost ILM. Sestavljen je iz 4 faz:
Vroče—indeks se aktivno posodablja in poizveduje.
Toplo - indeks se ne posodablja več, vendar je še vedno poizveden.
Hladno – Indeks se ne posodablja več in se po njem redko povprašujejo. Po informacijah bi moralo biti še vedno mogoče iskati, vendar bodo poizvedbe morda počasnejše.
Izbriši – kazalo ni več potrebno in ga lahko varno izbrišete.
Za razdelitev drobcev med vozlišča potrebujete samo en parameter:
Hot-vozlišča:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: hot
Toplo-vozlišča:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: warm
Hladno-vozlišča:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: cold
Nastavitev Logstash
Kako vse to deluje in kako smo implementirali to funkcijo? Začnimo s prenosom dnevnikov v Elasticsearch. Obstajata dva načina:
Logstash pridobi dnevnike iz Kafke. Lahko pobere čisto ali pretvori na stran.
Nekaj se zapiše v Elasticsearch, na primer strežnik APM.
Oglejmo si primer upravljanja indeksov prek Logstasha. Ustvari indeks in se uporabi predloga kazala in ustrezno ILM.
k8s-ingress.conf
input {
kafka {
bootstrap_servers => "node01, node02, node03"
topics => ["ingress-k8s"]
decorate_events => false
codec => "json"
}
}
filter {
ruby {
path => "/etc/logstash/conf.d/k8s-normalize.rb"
}
if [log] =~ "[warn]" or [log] =~ "[error]" or [log] =~ "[notice]" or [log] =~ "[alert]" {
grok {
match => { "log" => "%{DATA:[nginx][error][time]} [%{DATA:[nginx][error][level]}] %{NUMBER:[nginx][error][pid]}#%{NUMBER:[nginx][error][tid]}: *%{NUMBER:[nginx][error][connection_id]} %{DATA:[nginx][error][message]}, client: %{IPORHOST:[nginx][error][remote_ip]}, server: %{DATA:[nginx][error][server]}, request: "%{WORD:[nginx][error][method]} %{DATA:[nginx][error][url]} HTTP/%{NUMBER:[nginx][error][http_version]}", (?:upstream: "%{DATA:[nginx][error][upstream][proto]}://%{DATA:[nginx][error][upstream][host]}:%{DATA:[nginx][error][upstream][port]}/%{DATA:[nginx][error][upstream][url]}", )?host: "%{DATA:[nginx][error][host]}"(?:, referrer: "%{DATA:[nginx][error][referrer]}")?" }
remove_field => "log"
}
}
else {
grok {
match => { "log" => "%{IPORHOST:[nginx][access][host]} - [%{IPORHOST:[nginx][access][remote_ip]}] - %{DATA:[nginx][access][remote_user]} [%{HTTPDATE:[nginx][access][time]}] "%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][bytes_sent]} "%{DATA:[nginx][access][referrer]}" "%{DATA:[nginx][access][agent]}" %{NUMBER:[nginx][access][request_lenght]} %{NUMBER:[nginx][access][request_time]} [%{DATA:[nginx][access][upstream][name]}] (?:-|%{IPORHOST:[nginx][access][upstream][addr]}:%{NUMBER:[nginx][access][upstream][port]}) (?:-|%{NUMBER:[nginx][access][upstream][response_lenght]}) %{DATA:[nginx][access][upstream][response_time]} %{DATA:[nginx][access][upstream][status]} %{DATA:[nginx][access][request_id]}" }
remove_field => "log"
}
}
}
output {
elasticsearch {
id => "k8s-ingress"
hosts => ["node01", "node02", "node03", "node04", "node05", "node06", "node07", "node08"]
manage_template => true # включаем управление шаблонами
template_name => "k8s-ingress" # имя применяемого шаблона
ilm_enabled => true # включаем управление ILM
ilm_rollover_alias => "k8s-ingress" # alias для записи в индексы, должен быть уникальным
ilm_pattern => "{now/d}-000001" # шаблон для создания индексов, может быть как "{now/d}-000001" так и "000001"
ilm_policy => "k8s-ingress" # политика прикрепляемая к индексу
index => "k8s-ingress-%{+YYYY.MM.dd}" # название создаваемого индекса, может содержать %{+YYYY.MM.dd}, зависит от ilm_pattern
}
}
Postavitev Kibane
Obstaja osnovna predloga, ki velja za vse nove indekse. Nastavi porazdelitev vročih indeksov, število drobcev, replik itd. Teža predloge je določena z možnostjo order. Predloge z višjimi utežmi preglasijo obstoječe parametre predloge ali dodajo nove.
GET_template/privzeto
{
"default" : {
"order" : -1, # вес шаблона
"version" : 1,
"index_patterns" : [
"*" # применяем ко всем индексам
],
"settings" : {
"index" : {
"codec" : "best_compression", # уровень сжатия
"routing" : {
"allocation" : {
"require" : {
"box_type" : "hot" # распределяем только по горячим нодам
},
"total_shards_per_node" : "8" # максимальное количество шардов на ноду от одного индекса
}
},
"refresh_interval" : "5s", # интервал обновления индекса
"number_of_shards" : "8", # количество шардов
"auto_expand_replicas" : "0-1", # количество реплик на ноду от одного индекса
"number_of_replicas" : "1" # количество реплик
}
},
"mappings" : {
"_meta" : { },
"_source" : { },
"properties" : { }
},
"aliases" : { }
}
}
Nato uporabite preslikavo za indekse k8s-ingress-* z uporabo predloge z večjo težo.
Po uporabi vseh predlog uporabimo pravilnik ILM in začnemo spremljati življenjsko dobo indeksov.
PRIDOBITE _ilm/policy/k8s-ingress
{
"k8s-ingress" : {
"version" : 14,
"modified_date" : "2020-06-11T10:27:01.448Z",
"policy" : {
"phases" : {
"warm" : { # теплая фаза
"min_age" : "5d", # срок жизни индекса после ротации до наступления теплой фазы
"actions" : {
"allocate" : {
"include" : { },
"exclude" : { },
"require" : {
"box_type" : "warm" # куда перемещаем индекс
}
},
"shrink" : {
"number_of_shards" : 4 # обрезание индексов, т.к. у нас 4 ноды
}
}
},
"cold" : { # холодная фаза
"min_age" : "25d", # срок жизни индекса после ротации до наступления холодной фазы
"actions" : {
"allocate" : {
"include" : { },
"exclude" : { },
"require" : {
"box_type" : "cold" # куда перемещаем индекс
}
},
"freeze" : { } # замораживаем для оптимизации
}
},
"hot" : { # горячая фаза
"min_age" : "0ms",
"actions" : {
"rollover" : {
"max_size" : "50gb", # максимальный размер индекса до ротации (будет х2, т.к. есть 1 реплика)
"max_age" : "1d" # максимальный срок жизни индекса до ротации
},
"set_priority" : {
"priority" : 100
}
}
},
"delete" : { # фаза удаления
"min_age" : "120d", # максимальный срок жизни после ротации перед удалением
"actions" : {
"delete" : { }
}
}
}
}
}
}
Težave
Prišlo je do težav v fazi namestitve in odpravljanja napak.
Vroča faza
Za pravilno rotacijo indeksov, prisotnost na koncu index_name-date-000026 formatne številke 000001. V kodi so vrstice, ki na koncu preverjajo indekse z uporabo regularnega izraza za številke. V nasprotnem primeru bo prišlo do napake, politike ne bodo uporabljene za indeks in bo vedno v vroči fazi.
Topla faza
Shrink (rezanje) - zmanjšanje števila drobcev, ker imamo 4 vozlišča v topli in hladni fazi.V dokumentaciji so naslednje vrstice:
Indeks mora biti samo za branje.
Kopija vsakega drobca v indeksu mora biti v istem vozlišču.
Zdravstveno stanje grozda mora biti zeleno.
Za obrezovanje indeksa Elasticsearch premakne vse primarne drobce v eno vozlišče, podvoji obrezani indeks s potrebnimi parametri in nato izbriše starega. Parameter total_shards_per_node mora biti enako ali večje od števila glavnih drobcev, da se jih prilega enemu vozlišču. V nasprotnem primeru bodo obvestila in drobci se ne bodo premaknili na zahtevana vozlišča.
GET /shrink-k8s-ingress-2020.06.06-000025/_settings
Zamrzne (zamrznitev) - zamrznemo indeks za optimizacijo poizvedb na podlagi zgodovinskih podatkov.
Iskanja, izvedena na zamrznjenih indeksih, uporabljajo majhen, namenski niz niti z omejenim iskanjem za nadzor števila sočasnih iskanj, ki zadenejo zamrznjene drobce na vsakem vozlišču. To omejuje količino dodatnega pomnilnika, potrebnega za prehodne podatkovne strukture, ki ustrezajo zamrznjenim delcem, kar posledično ščiti vozlišča pred prekomerno porabo pomnilnika.
Zamrznjeni indeksi so samo za branje: vanje ne morete indeksirati.
Pričakuje se, da bodo iskanja po zamrznjenih indeksih potekala počasi. Zamrznjeni indeksi niso namenjeni veliki iskalni obremenitvi. Možno je, da iskanje po zamrznjenem indeksu traja nekaj sekund ali minut, tudi če so se ista iskanja končala v milisekundah, ko indeksi niso bili zamrznjeni.
Rezultati
Naučili smo se pripraviti vozlišča za delo z ILM, nastaviti predlogo za distribucijo shardov med vročimi vozlišči in konfigurirati ILM za indeks z vsemi življenjskimi fazami.