Dugotrajno skladištenje podataka u Elasticsearch-u
Moje ime je Igor Sidorenko, ja sam tehnički vođa u timu admina koji održava kompletnu infrastrukturu Domclicka.
Želim podijeliti svoje iskustvo u postavljanju distribuirane pohrane podataka u Elasticsearch. Pogledaćemo koja su podešavanja na čvorovima odgovorna za distribuciju šarda, kako ILM radi i radi.
Oni koji rade sa trupcima, na ovaj ili onaj način, suočavaju se s problemom dugotrajnog skladištenja za kasniju analizu. U Elasticsearch-u je to posebno tačno, jer je sve bilo nesretno sa funkcionalnošću kustosa. Verzija 6.6 uvela je ILM funkcionalnost. Sastoji se od 4 faze:
Vruće - Indeks se aktivno ažurira i postavlja upit.
Toplo - Indeks se više ne ažurira, ali se još uvijek postavlja upit.
Hladno - Indeks se više ne ažurira i rijetko se postavlja upit. Informacije i dalje moraju biti pretražive, ali upiti mogu biti sporiji.
Izbriši - Indeks više nije potreban i može se bezbedno izbrisati.
Za distribuciju krhotina po čvorovima potreban vam je samo jedan parametar:
Vruć-čvorovi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: hot
topao-čvorovi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: warm
hladan-čvorovi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: cold
Postavljanje Logstash-a
Kako sve to funkcionira i kako smo implementirali ovu funkciju? Počnimo s unosom logova u Elasticsearch. Postoje dva načina:
Logstash preuzima dnevnike od Kafke. Može se pokupiti čisto ili pretvoriti na vašoj strani.
Nešto samo piše u Elasticsearch, na primjer, APM server.
Razmotrite primjer upravljanja indeksima putem Logstash-a. Kreira indeks i primjenjuje se na njega indeksni obrazac i odgovarajući VRIJEME.
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
}
}
Kibana setup
Postoji osnovni obrazac koji se primjenjuje na sve nove indekse. Postavlja distribuciju vrućih indeksa, broj fragmenata, replika, itd. Težina šablona je određena opcijom order. Predlošci s većom težinom nadjačavaju postojeće parametre predloška ili dodaju nove.
GET_template/default
{
"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" : { }
}
}
Zatim primijenite mapiranje na indekse k8s-ingress-* korištenjem šablona veće težine.
Nakon primjene svih šablona, primjenjujemo ILM politiku i počinjemo pratiti životni vijek indeksa.
GET _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" : { }
}
}
}
}
}
}
Problemi
Bilo je problema u fazi postavljanja i otklanjanja grešaka.
Vruća faza
Za ispravnu rotaciju indeksa, prisustvo na kraju je kritično index_name-date-000026 formatirajte brojeve 000001. Postoje redovi u kodu koji provjeravaju indekse koristeći regularni izraz za prisustvo brojeva na kraju. U suprotnom će doći do greške, nikakve politike neće biti primijenjene na indeks i on će uvijek biti u vrućoj fazi.
Topla faza
Shrink (cutoff) — smanjenje broja krhotina, jer imamo 4 čvora u toploj i hladnoj fazi. Dokumentacija sadrži sljedeće redove:
Indeks mora biti samo za čitanje.
Kopija svakog šarda u indeksu mora se nalaziti na istom čvoru.
Zdravstveni status klastera mora biti zelen.
Da bi smanjio indeks, Elasticsearch premješta sve primarne dijelove na jedan čvor, duplicira skraćeni indeks s potrebnim parametrima, a zatim briše stari. Parametar total_shards_per_node mora biti jednak ili veći od broja glavnih dijelova da stane na jedan čvor. U suprotnom će biti obavještenja i dijelovi se neće premjestiti na ispravne čvorove.
GET /shrink-k8s-ingress-2020.06.06-000025/_settings
zamrzavanje (zamrzavanje) - Zamrzavamo indeks da bismo optimizirali upite o istorijskim podacima.
Pretrage koje se izvode na zamrznutim indeksima koriste mali, namjenski, search_throttled threadpool za kontrolu broja istovremenih pretraga koje pogađaju zamrznute dijelove na svakom čvoru. Ovo ograničava količinu dodatne memorije potrebne za prolazne strukture podataka koje odgovaraju zamrznutim dijelovima, što posljedično štiti čvorove od prekomjerne potrošnje memorije.
Zamrznuti indeksi su samo za čitanje: ne možete indeksirati u njih.
Očekuje se da će pretrage na zamrznutim indeksima biti sporo. Zamrznuti indeksi nisu namijenjeni za veliko opterećenje pretraživanja. Moguće je da pretraga zamrznutog indeksa može potrajati nekoliko sekundi ili minuta da se završi, čak i ako su ista pretraživanja završena u milisekundama kada indeksi nisu bili zamrznuti.
Ishodi
Naučili smo kako pripremiti čvorove za rad sa ILM-om, postaviti predložak za distribuciju krhotina među vrućim čvorovima i postaviti ILM za indeks sa svim fazama života.