Mit navn er Igor Sidorenko, jeg er en teknisk leder i teamet af administratorer, der vedligeholder hele Domclicks infrastruktur.
Jeg vil gerne dele min erfaring med at opsætte distribueret datalagring i Elasticsearch. Vi vil se på, hvilke indstillinger på noderne, der er ansvarlige for fordelingen af shards, hvordan ILM fungerer og virker.
De, der arbejder med logs, på den ene eller anden måde, står over for problemet med langtidsopbevaring til senere analyse. I Elasticsearch gælder det især, fordi alt var uheldigt med kuratorfunktionaliteten. Version 6.6 introducerede ILM-funktionalitet. Den består af 4 faser:
Hot - Indekset bliver aktivt opdateret og forespurgt.
Varm - Indekset opdateres ikke længere, men bliver stadig forespurgt.
Kold - Indekset opdateres ikke længere og spørges sjældent til. Oplysningerne skal stadig være søgbare, men forespørgsler kan være langsommere.
Slet - Indekset er ikke længere nødvendigt og kan sikkert slettes.
Disse indstillinger er individuelle, det hele afhænger af stedet på noderne, antallet af indekser, logfiler osv. Vi har 2-3 TB data om dagen.
5 dage - Varm fase (8 hoved / 1 replika).
20 dage - Varm fase (krympe-indeks 4 hoved / 1 replika).
90 dage - kold fase (fryse-indeks 4 hoved / 1 replika).
120 dage - Slet fase.
Opsætning af Elasticsearch
For at fordele shards på tværs af noder behøver du kun én parameter:
varm-knuder:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: hot
Varm-knuder:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: warm
Forkølelse-knuder:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: cold
Opsætning af Logstash
Hvordan fungerer det hele, og hvordan implementerede vi denne funktion? Lad os starte med at få logs ind i Elasticsearch. Der er to måder:
Logstash henter logs fra Kafka. Kan afhente rent eller konvertere på din side.
Noget selv skriver til Elasticsearch, for eksempel en APM-server.
Overvej et eksempel på styring af indekser gennem Logstash. Det opretter et indeks og anvender det indeksmønster og tilsvarende 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
}
}
Kibana opsætning
Der er et basismønster, der gælder for alle nye indekser. Den indstiller fordelingen af varme indekser, antallet af shards, replikaer osv. Skabelonens vægt bestemmes af muligheden order. Skabeloner med en højere vægt tilsidesætter eksisterende skabelonparametre eller tilføjer nye.
GET_skabelon/standard
{
"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" : { }
}
}
Anvend derefter tilknytningen til indekserne k8s-ingress-* ved hjælp af en skabelon med en højere vægt.
Efter at have anvendt alle skabelonerne anvender vi ILM-politikken og begynder at overvåge indeksernes levetid.
FÅ _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" : { }
}
}
}
}
}
}
Problemer
Der var problemer på opsætnings- og fejlfindingsstadiet.
Varm fase
For den korrekte rotation af indekser er tilstedeværelsen i slutningen afgørende index_name-date-000026 formatere tal 000001. Der er linjer i koden, der kontrollerer indekser ved hjælp af et regulært udtryk for tilstedeværelsen af tal i slutningen. Ellers vil der være en fejl, ingen politikker vil blive anvendt på indekset, og det vil altid være i den varme fase.
Varm fase
Shrink (cutoff) — reduktion af antallet af shards, fordi vi har 4 noder i den varme og kolde fase. Dokumentationen indeholder følgende linjer:
Indekset skal være skrivebeskyttet.
En kopi af hvert shard i indekset skal ligge på den samme node.
Klyngens sundhedsstatus skal være grøn.
For at beskære et indeks flytter Elasticsearch alle primære shards til én node, duplikerer det trunkerede indeks med de nødvendige parametre og sletter derefter det gamle. Parameter total_shards_per_node skal være lig med eller større end antallet af hovedskår for at passe på én knude. Ellers vil der være meddelelser, og shards vil ikke flytte til de korrekte noder.
GET /shrink-k8s-ingress-2020.06.06-000025/_settings
Frys (frys) - Vi fryser indekset for at optimere forespørgsler på historiske data.
Søgninger udført på frosne indekser bruger den lille, dedikerede, search_throttled threadpool til at kontrollere antallet af samtidige søgninger, der rammer frosne shards på hver node. Dette begrænser mængden af ekstra hukommelse, der kræves til de transiente datastrukturer svarende til frosne shards, som følgelig beskytter noder mod for stort hukommelsesforbrug.
Frosne indekser er skrivebeskyttede: du kan ikke indeksere dem.
Søgninger på frosne indekser forventes at udføres langsomt. Frosne indekser er ikke beregnet til høj søgebelastning. Det er muligt, at en søgning på et fastfrosset indeks kan tage sekunder eller minutter at fuldføre, selvom de samme søgninger blev udført på millisekunder, når indeksene ikke blev frosset.
Resultaterne af
Vi lærte at forberede noder til at arbejde med ILM, opsætte en skabelon til fordeling af shards blandt hot noder og opsætte ILM til et indeks med alle livsfaser.