
Mano vardas Igoris Sidorenko, esu techninis vadovas administratorių komandoje, kuri prižiūri visą Domclick infrastruktūrą.
Noriu pasidalinti savo patirtimi nustatant paskirstytą duomenų saugyklą Elasticsearch. Pažiūrėsime, kokie mazgų nustatymai yra atsakingi už šukių paskirstymą, kaip veikia ir veikia ILM.
Tie, kurie dirba su rąstais, vienaip ar kitaip, susiduria su ilgalaikio saugojimo problema vėlesnei analizei. Elasticsearche tai ypač aktualu, nes su kuratoriaus funkcionalumu viskas buvo gaila. 6.6 versija pristatė ILM funkciją. Jį sudaro 4 fazės:
- Karšta – indeksas aktyviai atnaujinamas ir užklausa.
- Šilta – indeksas nebeatnaujinamas, bet vis dar tebeklausomas.
- Šaltas – indeksas nebeatnaujinamas ir retai užklausa. Informacijos vis tiek turi būti galima ieškoti, tačiau užklausos gali būti lėtesnės.
- Ištrinti – indeksas nebereikalingas ir jį galima saugiai ištrinti.
Duota
- „Elasticsearch Data Hot“: 24 procesoriai, 128 GB atmintis, 1,8 TB SSD RAID 10 (8 mazgai).
- „Elasticsearch Data Warm“: 24 procesoriai, 64 GB atmintis, 8 TB „NetApp“ SSD politika (4 mazgai).
- Elasticsearch Data Cold: 8 procesoriai, 32 GB atmintis, 128 TB HDD RAID 10 (4 mazgai).
Tikslas
Šie nustatymai yra individualūs, viskas priklauso nuo mazgų vietos, indeksų skaičiaus, žurnalų ir kt. Per dieną turime 2–3 TB duomenų.
- 5 dienos – karštoji fazė (8 pagrindinės / 1 kopija).
- 20 dienų – šiltoji fazė ( 4 pagrindinės / 1 kopija).
- 90 dienų – šaltoji fazė ( 4 pagrindinės / 1 kopija).
- 120 dienų – ištrynimo fazė.
„Elasticsearch“ nustatymas
Norėdami paskirstyti skeveldrą tarp mazgų, jums reikia tik vieno parametro:
- karštas- mazgai:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr # Add custom attributes to the node: node.attr.box_type: hot - Šiltas- mazgai:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr # Add custom attributes to the node: node.attr.box_type: warm - Šalta- mazgai:
~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr # Add custom attributes to the node: node.attr.box_type: cold
„Logstash“ nustatymas
Kaip visa tai veikia ir kaip įdiegėme šią funkciją? Pradėkime nuo prisijungimo prie Elasticsearch. Yra du būdai:
- Logstash atneša rąstus iš Kafkos. Galima pasiimti švariai arba konvertuoti ant šono.
- Kažkas pats rašo į Elasticsearch, pavyzdžiui, APM serveris.
Apsvarstykite indeksų valdymo per „Logstash“ pavyzdį. Jis sukuria indeksą ir jam pritaiko ir atitinkamas .
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
}
}
Kibanos sąranka
Yra bazinis modelis, kuris taikomas visiems naujiems indeksams. Jis nustato karštųjų indeksų pasiskirstymą, šukių, kopijų skaičių ir kt. Šablono svoris nustatomas pagal pasirinktį order. Didesnio svorio šablonai nepaiso esamų šablonų parametrų arba prideda naujų.


GAUTI _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" : { }
}
}
Tada pritaikykite indeksams susiejimą k8s-ingress-* naudojant didesnio svorio šabloną.


GAUTI _template/k8s-ingress
{
"k8s-ingress" : {
"order" : 100,
"index_patterns" : [
"k8s-ingress-*"
],
"settings" : {
"index" : {
"lifecycle" : {
"name" : "k8s-ingress",
"rollover_alias" : "k8s-ingress"
},
"codec" : "best_compression",
"routing" : {
"allocation" : {
"require" : {
"box_type" : "hot"
}
}
},
"number_of_shards" : "8",
"number_of_replicas" : "1"
}
},
"mappings" : {
"numeric_detection" : false,
"_meta" : { },
"_source" : { },
"dynamic_templates" : [
{
"all_fields" : {
"mapping" : {
"index" : false,
"type" : "text"
},
"match" : "*"
}
}
],
"date_detection" : false,
"properties" : {
"kubernetes" : {
"type" : "object",
"properties" : {
"container_name" : {
"type" : "keyword"
},
"container_hash" : {
"index" : false,
"type" : "keyword"
},
"host" : {
"type" : "keyword"
},
"annotations" : {
"type" : "object",
"properties" : {
"value" : {
"index" : false,
"type" : "text"
},
"key" : {
"index" : false,
"type" : "keyword"
}
}
},
"docker_id" : {
"index" : false,
"type" : "keyword"
},
"pod_id" : {
"type" : "keyword"
},
"labels" : {
"type" : "object",
"properties" : {
"value" : {
"type" : "keyword"
},
"key" : {
"type" : "keyword"
}
}
},
"namespace_name" : {
"type" : "keyword"
},
"pod_name" : {
"type" : "keyword"
}
}
},
"@timestamp" : {
"type" : "date"
},
"nginx" : {
"type" : "object",
"properties" : {
"access" : {
"type" : "object",
"properties" : {
"agent" : {
"type" : "text"
},
"response_code" : {
"type" : "integer"
},
"upstream" : {
"type" : "object",
"properties" : {
"port" : {
"type" : "keyword"
},
"name" : {
"type" : "keyword"
},
"response_lenght" : {
"type" : "integer"
},
"response_time" : {
"index" : false,
"type" : "text"
},
"addr" : {
"type" : "keyword"
},
"status" : {
"index" : false,
"type" : "text"
}
}
},
"method" : {
"type" : "keyword"
},
"http_version" : {
"type" : "keyword"
},
"bytes_sent" : {
"type" : "integer"
},
"request_lenght" : {
"type" : "integer"
},
"url" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword"
}
}
},
"remote_user" : {
"type" : "text"
},
"referrer" : {
"type" : "text"
},
"remote_ip" : {
"type" : "ip"
},
"request_time" : {
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
"type" : "date"
},
"host" : {
"type" : "keyword"
},
"time" : {
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
"type" : "date"
}
}
},
"error" : {
"type" : "object",
"properties" : {
"server" : {
"type" : "keyword"
},
"upstream" : {
"type" : "object",
"properties" : {
"port" : {
"type" : "keyword"
},
"proto" : {
"type" : "keyword"
},
"host" : {
"type" : "keyword"
},
"url" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword"
}
}
}
}
},
"method" : {
"type" : "keyword"
},
"level" : {
"type" : "keyword"
},
"http_version" : {
"type" : "keyword"
},
"pid" : {
"index" : false,
"type" : "integer"
},
"message" : {
"type" : "text"
},
"tid" : {
"index" : false,
"type" : "keyword"
},
"url" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword"
}
}
},
"referrer" : {
"type" : "text"
},
"remote_ip" : {
"type" : "ip"
},
"connection_id" : {
"index" : false,
"type" : "keyword"
},
"host" : {
"type" : "keyword"
},
"time" : {
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
"type" : "date"
}
}
}
}
},
"log" : {
"type" : "text"
},
"@version" : {
"type" : "text",
"fields" : {
"keyword" : {
"ignore_above" : 256,
"type" : "keyword"
}
}
},
"eventtime" : {
"type" : "float"
}
}
},
"aliases" : { }
}
}
Pritaikę visus šablonus taikome ILM politiką ir pradedame stebėti indeksų gyvavimo laiką.



GAUTI _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" : { }
}
}
}
}
}
}
Problemos
Sąrankos ir derinimo etape kilo problemų.
Karšta fazė
Norint teisingai suktis indeksus, buvimas pabaigoje yra labai svarbus index_name-date-000026 formato numeriai 000001. Kode yra eilučių, kurios tikrina indeksus naudojant reguliariąją išraišką, ar pabaigoje yra skaičių. Priešingu atveju įvyks klaida, indeksui nebus taikoma politika ir jis visada bus karštoje fazėje.
Šilta fazė
trauktis (cutoff) — šukių skaičiaus mažinimas, nes turime 4 mazgus šiltoje ir šaltoje fazėje. Dokumentacijoje yra šios eilutės:
- Indeksas turi būti tik skaitomas.
- Kiekvienos indekso skeveldros kopija turi būti tame pačiame mazge.
- Klasterio sveikatos būklė turi būti žalia.
Kad apkarpytų indeksą, Elasticsearch perkelia visas pirmines skeveldras į vieną mazgą, sutrumpina indeksą su reikiamais parametrais ir ištrina senąjį. Parametras total_shards_per_node turi būti lygus arba didesnis už pagrindinių skeveldrų skaičių, kad tilptų viename mazge. Priešingu atveju bus pranešta, o šukės neperkels į reikiamus mazgus.


GET /shrink-k8s-ingress-2020.06.06-000025/_settings
{
"shrink-k8s-ingress-2020.06.06-000025" : {
"settings" : {
"index" : {
"refresh_interval" : "5s",
"auto_expand_replicas" : "0-1",
"blocks" : {
"write" : "true"
},
"provided_name" : "shrink-k8s-ingress-2020.06.06-000025",
"creation_date" : "1592225525569",
"priority" : "100",
"number_of_replicas" : "1",
"uuid" : "psF4MiFGQRmi8EstYUQS4w",
"version" : {
"created" : "7060299",
"upgraded" : "7060299"
},
"lifecycle" : {
"name" : "k8s-ingress",
"rollover_alias" : "k8s-ingress",
"indexing_complete" : "true"
},
"codec" : "best_compression",
"routing" : {
"allocation" : {
"initial_recovery" : {
"_id" : "_Le0Ww96RZ-o76bEPAWWag"
},
"require" : {
"_id" : null,
"box_type" : "cold"
},
"total_shards_per_node" : "8"
}
},
"number_of_shards" : "4",
"routing_partition_size" : "1",
"resize" : {
"source" : {
"name" : "k8s-ingress-2020.06.06-000025",
"uuid" : "gNhYixO6Skqi54lBjg5bpQ"
}
}
}
}
}
}
Šalta fazė
Užšaldyti (užšaldyti) – sustabdome indeksą, kad optimizuotume istorinių duomenų užklausas.
Paieškos, atliekamos pagal fiksuotus indeksus, naudoja nedidelę, skirtą, „Search_throttled“ gijų grupę, kad būtų galima valdyti tuo pačiu metu atliekamų paieškų, kurių kiekviename mazge buvo užfiksuotos skeveldros, skaičių. Tai riboja papildomos atminties kiekį, reikalingą trumpalaikėms duomenų struktūroms, atitinkančioms užšaldytus fragmentus, o tai apsaugo mazgus nuo per didelio atminties suvartojimo.
Užšaldyti indeksai yra tik skaitomi: jų negalima indeksuoti.
Numatoma, kad užšaldytų indeksų paieškos bus vykdomos lėtai. Užšaldyti indeksai nėra skirti dideliam paieškos apkrovimui. Gali būti, kad fiksuoto indekso paieška gali užtrukti kelias sekundes ar minutes, net jei tos pačios paieškos buvo baigtos per milisekundes, kai indeksai nebuvo fiksuoti.
rezultatai
Sužinojome, kaip paruošti mazgus darbui su ILM, nustatyti šabloną skeveldrų paskirstymui tarp karštųjų mazgų ir nustatyti ILM indeksui su visais gyvenimo etapais.
Naudingos nuorodos
Šaltinis: www.habr.com
