Archiviazione di dati à longu andà in Elasticsearch
Mi chjamu Igor Sidorenko, sò un capu tecnicu in una squadra di amministratori chì mantene tutta l'infrastruttura Domklik in ordine.
Vogliu sparte a mo spirienza in a stallazione di u almacenamentu di dati distribuitu in Elasticsearch. Fighjemu quali paràmetri nantu à i nodi sò rispunsevuli di a distribuzione di shards, cumu ILM hè strutturatu è travaglia.
Quelli chì travaglianu cù logs sò un modu o un altru affruntatu cù u prublema di almacenamiento à longu andà per l'analisi sussegwente. Questu hè soprattuttu veru in Elasticsearch perchè a funziunalità di u curatore hè stata terribili. In a versione 6.6, a funziunalità ILM apparsu. Hè custituitu di 4 fasi:
Hot - L'indice hè attivamente aghjurnatu è interrugatu.
Warm - l'indici ùn hè più aghjurnatu, ma hè sempre interrugatu.
Cold - L'indici ùn hè più aghjurnatu è hè raramente interrugatu. L'infurmazione deve esse sempre cercabile, ma e dumande pò esse più lente.
Elimina - L'indici ùn hè più necessariu è pò esse eliminatu in modu sicuru.
Datu
Elasticsearch Data Hot: 24 processori, 128 GB di memoria, 1,8 TB SSD RAID 10 (8 nodi).
Elasticsearch Data Warm: 24 processori, 64 GB di memoria, 8 TB NetApp SSD Policy (4 nodi).
Elasticsearch Data Cold: 8 processori, 32 GB di memoria, 128 TB HDD RAID 10 (4 nodi).
Goal
Questi paràmetri sò individuali, tuttu dipende di u spaziu nantu à i nodi, u numeru di indici, logs, etc. Per noi questu hè 2-3 TB di dati per ghjornu.
5 ghjorni - Fase calda (8 principale / 1 replica).
Per distribuisce frammenti trà i nodi, avete bisognu solu un paràmetru:
Hot-nodi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: hot
Warm-nodi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: warm
tinsioni-nodi:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
# Add custom attributes to the node:
node.attr.box_type: cold
Configurazione di Logstash
Cumu funziona tuttu questu è cumu implementemu sta funzione? Cuminciamu cù i logs in Elasticsearch. Ci sò dui maneri:
Logstash recupera logs da Kafka. Pò ripiglià pulita o cunvertisce da u so latu.
Qualcosa si scrive in Elasticsearch, per esempiu, un servitore APM.
Fighjemu un esempiu di gestione d'indici attraversu Logstash. Crea un indice è s'applica mudellu di indice è currispundenti 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
}
}
A creazione di Kibana
Ci hè un mudellu di basa chì si applica à tutti i novi indici. Stabilisce a distribuzione di l'indici caldi, u numeru di shards, repliche, etc. U pesu di u mudellu hè determinatu da l'opzione order. I mudelli cù pesi più alti annullanu i paràmetri di mudelli esistenti o aghjunghjenu novi.
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" : { }
}
}
Allora applicà a mappatura à l'indici k8s-ingress-* usendu un mudellu cù un pesu più altu.
Dopu avè applicà tutti i mudelli, applichemu a pulitica ILM è cuminciamu à seguità a vita di l'indici.
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
Ci sò stati prublemi in u stadiu di setup è debugging.
Fase calda
Per a rotazione curretta di l'indici, a prisenza à a fine di index_name-date-000026 numeri di furmatu 000001. Ci sò linii in u codice chì verificanu l'indici utilizendu una espressione regulare per i numeri à a fine. Altrimenti, ci sarà un errore, e pulitiche ùn saranu micca applicate à l'indici è serà sempre in a fase calda.
Fase calda
Shrink (cutting) - riducendu u numeru di shards, perchè avemu 4 nodi in i fasi caldi è friddi A ducumentazione cuntene e seguenti linee:
L'indici deve esse di sola lettura.
Una copia di ogni shard in l'indici deve reside nantu à u stessu node.
U statu di salute di u cluster deve esse verde.
Per trim un indice, Elasticsearch move tutti i frammenti primari à un node, duplicate l'indici trimmed cù i paràmetri necessarii, è poi sguassate u vechju. Parametru total_shards_per_node deve esse uguale o più grande di u numeru di frammenti principali per mette in un node. Altrimenti, ci saranu notificazioni è i frammenti ùn si moveranu micca in i nodi necessarii.
GET /shrink-k8s-ingress-2020.06.06-000025/_settings
to freeze (freeze) - congelamu l'indici per ottimisà e dumande basate nantu à dati storichi.
Ricerche realizate nantu à l'indici congelati utilizanu u picculu filu di fili, dedicatu, search_throttled per cuntrullà u nùmeru di ricerche simultanee chì toccanu frammenti congelati in ogni node. Questu limita a quantità di memoria extra necessaria per e strutture di dati transitori chì currispondenu à i frammenti congelati, chì per quessa prutegge i nodi da u cunsumu eccessivu di memoria.
L'indici congelati sò di sola lettura: ùn pudete micca indexà in elli.
E ricerche nantu à l'indici congelati sò previsti per eseguisce lentamente. L'indici congelati ùn sò micca destinati à una alta carica di ricerca. Hè pussibule chì una ricerca di un indice congelatu pò piglià sicondi o minuti per compie, ancu s'è e stesse ricerche cumpletu in millisecondi quandu l'indici ùn eranu micca congelati.
Risultati
Avemu amparatu à preparà i nodi per travaglià cù ILM, cunfigurà un mudellu per a distribuzione di frammenti trà i nodi caldi, è cunfiguratu ILM per un indice cù tutte e fasi di vita.