Jmenuji se Igor Sidorenko, jsem technický vedoucí v týmu adminů, kteří spravují celou infrastrukturu Domclick.
Chci se podělit o své zkušenosti s nastavením distribuovaného úložiště dat v Elasticsearch. Podíváme se, jaká nastavení na uzlech jsou zodpovědná za distribuci shardů, jak funguje a funguje ILM.
Ti, kteří pracují s protokoly, tak či onak, čelí problému dlouhodobého ukládání pro pozdější analýzu. V Elasticsearch to platí obzvlášť, protože vše bylo nešťastné s funkčností kurátoru. Verze 6.6 zavedla funkcionalitu ILM. Skládá se ze 4 fází:
Hot – Index je aktivně aktualizován a dotazován.
Teplý – Index již není aktualizován, ale stále se na něj dotazuje.
Studený – Index již není aktualizován a dotazován je jen zřídka. Informace musí být stále vyhledatelné, ale dotazy mohou být pomalejší.
Smazat – Index již není potřeba a lze jej bezpečně smazat.
90 dní – studená fáze (freeze-index 4 hlavní / 1 replika).
120 dní - Smazat fázi.
Nastavení Elasticsearch
Chcete-li distribuovat fragmenty mezi uzly, potřebujete pouze jeden parametr:
Hot-uzly:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: hot
Teplý-uzly:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: warm
Studený-uzly:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: cold
Nastavení Logstash
Jak to celé funguje a jak jsme tuto funkci implementovali? Začněme získáním logů do Elasticsearch. Existují dva způsoby:
Logstash stahuje protokoly od Kafky. Může vyzvednout čisté nebo převést na vaší straně.
Něco samo zapisuje do Elasticsearch, například server APM.
Zvažte příklad správy indexů prostřednictvím Logstash. Vytvoří index a použije se na něj indexový vzor a odpovídající 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
}
}
Nastavení Kibana
Existuje základní vzor, který platí pro všechny nové indexy. Nastavuje distribuci horkých indexů, počet střepů, replik atd. Hmotnost šablony je určena volbou order. Šablony s vyšší váhou přepíší stávající parametry šablony nebo přidají nové.
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" : { }
}
}
Poté aplikujte mapování na indexy k8s-ingress-* pomocí šablony s vyšší gramáží.
Po aplikaci všech šablon aplikujeme politiku ILM a začneme sledovat životnost indexů.
ZÍSKEJTE _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" : { }
}
}
}
}
}
}
Problémy
Vyskytly se problémy ve fázi nastavení a ladění.
Horká fáze
Pro správnou rotaci indexů je přítomnost na konci kritická index_name-date-000026 formátovat čísla 000001. V kódu jsou řádky, které kontrolují indexy pomocí regulárního výrazu na přítomnost čísel na konci. V opačném případě dojde k chybě, na index nebudou aplikovány žádné zásady a bude vždy v horké fázi.
Teplá fáze
Scvrknout se (cutoff) — snížení počtu střepů, protože máme 4 uzly v teplé a studené fázi. Dokumentace obsahuje následující řádky:
Index musí být pouze pro čtení.
Kopie každého fragmentu v indexu musí být umístěna ve stejném uzlu.
Stav klastru musí být zelený.
Pro oříznutí indexu přesune Elasticsearch všechny primární fragmenty do jednoho uzlu, duplikuje zkrácený index s nezbytnými parametry a poté odstraní starý. Parametr total_shards_per_node musí být stejný nebo větší než počet hlavních úlomků, aby se vešly na jeden uzel. V opačném případě budou upozornění a úlomky se nepřesunou do správných uzlů.
GET /shrink-k8s-ingress-2020.06.06-000025/_settings
Vyhledávání prováděná na zmrazených indexech používají malý, vyhrazený, search_throttled threadpool k řízení počtu souběžných vyhledávání, která zasáhla zmrazené úlomky na každém uzlu. To omezuje množství paměti navíc potřebné pro přechodné datové struktury odpovídající zmrazeným úlomkům, což následně chrání uzly před nadměrnou spotřebou paměti.
Zmrazené indexy jsou pouze pro čtení: nelze do nich indexovat.
Očekává se, že vyhledávání na zmrazených indexech bude probíhat pomalu. Zmrazené indexy nejsou určeny pro vysokou vyhledávací zátěž. Je možné, že dokončení vyhledávání zmrazeného indexu může trvat sekundy nebo minuty, i když stejná vyhledávání byla dokončena v milisekundách, když indexy nebyly zmrazeny.
Výsledky
Naučili jsme se připravit uzly pro práci s ILM, nastavit šablonu pro distribuci shardů mezi horké uzly a nastavit ILM pro index se všemi fázemi života.