
Shumë njerëz përballen me Elasticsearch. Por çfarë ndodh kur dëshiron ta përdorësh për të ruajtur log-et "në sasi të mëdha"? Dhe si mund të përballosh dështimin e ndonjë qendre të të dhënave pa stres? Si duhet të jetë arkitektura dhe cilat pengesa të padukshme mund të hasësh?
Ne në Odnoklassniki vendosëm të zgjidhim çështjen e menaxhimit të log-eve me elasticsearch, dhe tani po ndajem përvojën tonë me Habra: jo vetëm për arkitekturën, por edhe për pengesat.
Unë jam Pyotr Zaytsev, punoj si administrator sistemi në Odnoklassniki. Para kësaj isha gjithashtu administrator, kam punuar me Manticore Search, Sphinx search, Elasticsearch. Mundësisht, nëse shfaqet ndonjë motor tjetër kërkimi, ndoshta do të punoj edhe me të. Kam marrë pjesë gjithashtu në disa projekte open-source në mënyrë vullnetarizmi.
Kur bëra intervistën për punë në Odnoklassniki, me guxim thashë se dinja të punoja me Elasticsearch. Pas disa detyrave të thjeshta, më dhanë një sfidë të madhe për reforma në sistemin e menaxhimit të log-eve që ekzistonte në atë kohë.
Kërkesat
Kërkesat për sistemin ishin formuluar si më poshtë:
- Si frontend duhej të përdorej Graylog. Sepse kompania kishte përvojë me këtë produkt, programuesit dhe testerët e njihnin, e kishin të njohur dhe të përshtatshëm.
- Sasia e të dhënave: mesatarisht 50-80 mijë mesazhe në sekondë, por nëse ndodh ndonjë problem, trafiku nuk ka kufizim, mund të arrijë 2-3 milion rreshta në sekondë.
- Pas diskutimeve me klientët mbi kërkesat për shpejtësinë e përpunimit të kërkesave, kuptuam se modeli i zakonshëm i përdorimit të një sistemi të tillë është: njerëzit kërkojnë log-et e aplikacionit të tyre për dy ditët e fundit dhe nuk duan të presin më shumë se një sekondë për rezultatet e kërkesës.
- Administratoret insistuan që sistemi duhet të ishte lehtësisht i shkallëzueshëm, pa kërkuar një shkallë të thellë kuptimi se si ishte ndërtuar.
- Që detyra e vetme e mirëmbajtjes që këto sisteme kërkonin herë pas here ishte të ndryshohej ndonjë harduer.
- Për më tepër, në Odnoklassniki ekziston një traditë teknike e shkëlqyer: çdo shërbim që ne lançojmë duhet të përballojë dështimin e një qendre të të dhënash (të papritur, të paplanifikuar dhe në çdo moment).
Kërkesa e fundit për realizimin e këtij projekti ishte më e vështirë, për të cilën do të flas më në detaje më vonë.
Mjedisi
Ne punojmë në katër qendra të të dhënave, ndërkohë që nodet e të dhënave Elasticsearch mund të ndodhen vetëm në tri (për disa arsye jo teknike).
Në këto katër qendra të të dhënave ka rreth 18 mijë burime të ndryshme log-esh — pajisje, konteinerë, makineri virtuale.
Një veçori e rëndësishme: ngritja e klasters bëhet në konteinerë jo në makinat fizike, por në . Konteinerëve u garantohen 2 bërthama, të ngjashme me 2.0Ghz v4 me mundësi të riciklimit të bërthamave të tjera në rast pushimi.
Me fjalë të tjera:

Topologjia
Pamja e përgjithshme e zgjidhjes më dukej fillimisht kështu:
- 3-4 VIP janë pas A-record-it të domenit Graylog, kjo është adresa në të cilën dërgohen log-et.
- çdo VIP përfaqëson një balancues LVS.
- Pasi që log-et kalojnë në një bateri Graylog, pjesa e të dhënave shkon në formatin GELF, pjesa tjetër në formatin syslog.
- Më pas, të gjitha këto shkruhen në grupe të mëdha në një bateri të koordinatave Elasticsearch.
- Dhe ata, nga ana e tyre, dërgojnë kërkesat për të shkruar dhe për të lexuar tek nodet e të dhënave përkatëse.

Termat
Ndoshta, jo të gjithë janë të njohur me terminologjinë, kështu që do doja të ndalesha pak mbi të.
Në Elasticsearch ka disa lloje nodësh - master, coordinator, data node. Ka edhe dy lloje të tjera për përpunime të ndryshme log-esh dhe lidhjen e grupeve të ndryshme mes tyre, por ne përdorëm vetëm llojet e përmendura.
Master
Pinguese të gjithë nodet e pranishme në klaster, mbështet hartën e aktualizuar të klasterit dhe e shpërndan atë mes nodëve, trajton logjikën e ngjarjeve, merret me një sërë të tashme të mirëmbajtjes të klasterëve.
Koordinatori
Kryen një detyrë të vetme: pranon kërkesat nga klientët për të lexuar ose shkruar dhe drejton atë trafik. Në rast se kërkesa është për të shkruar, shumë mund të pyesë master-in se në cilin shard të indeksit përkatës duhet ta vendosë këtë, dhe do ta drejtojë kërkesën më tej.
Data node
Ruan të dhënat, kryen kërkesat e kërkimeve që mbërrijnë nga jashtë dhe operacionet mbi shard-et që ndodhen mbi të.
Graylog
Ky është diçka si një përzierje Kibana me Logstash në grumbullin ELK. Graylog kombinon si UI ashtu edhe një proces për përpunimin e logs. Nën kapak, Graylog përdor Kafka dhe Zookeeper, të cilat sigurojnë lidhjen e Graylog si klaster. Graylog është në gjendje të ruajë logs (Kafka) në rast të papërmbushjes së Elasticsearch dhe të përsërisë kërkesat e dështuara për lexim dhe shkruajmë, grupuan dhe etiketuan logs sipas rregullave të përcaktuara. Si Logstash, Graylog ka funksionalitetin për të modifikuar stringjet përpara se t'i shkruajë në Elasticsearch.
Përveç kësaj, në Graylog ka një zbulim shërbimi të integruar, duke lejuar që mbi një nodë të disponueshme Elasticsearch të merret e gjithë harta e klasterit dhe të filtrohet sipas një etikete të caktuar, duke lejuar kështu dërgimin e kërkesave në konteinerë specifikë.
Vizualisht, kjo duket afërsisht kështu:

Ky është një ekranik nga një instancë specifike. Këtu ne ndërtuam një histogramë sipas kërkesës së kërkimit, duke nxjerrë stringjet relevante.
Indeksat
Duke u rikthyer në arkitekturën e sistemit, do të doja të fokusoja më shumë në mënyrën se si e ndërtuam modelin e indekseve, në mënyrë që gjithçka të funksiononte siç duhet.
Në diagramin e treguar më parë, ky është niveli më i ulët: nodet e dhënave Elasticsearch.
Indeksi është një entitet i madh virtual, i përbërë nga sharda Elasticsearch. Vetë çdo shard nuk është asgjë tjetër veçse një indeks Lucene. Çdo indeks Lucene, për më tepër, përbëhet nga një ose më shumë segmente.

Për të ndërtuar sistemin, ne konsideruam se për të përmbushur kërkesat për shpejtësinë e leximit në një volum të madh të dhënash, ne duhej të "shpërndanim" këto të dhëna në mënyrë të barabartë në nodet e dhënave.
Kjo çoi në faktin se numri i shardeve për indeks (me replika) duhet të ishte saktësisht i barabartë me numrin e nodet e dhënave. Së pari, për të siguruar një faktor replike të barabartë me dy (dmth, ne mund të humbasim gjysmën e klasterit). Dhe, për më tepër, për të përpunuar kërkesat për lexim dhe shkruajmë, si të paktën në gjysmën e klasterit.
Koha e ruajtjes e vendosëm fillimisht si 30 ditë.
Shpërndarja e shardeve mund të paraqitet vizualisht ashtu si më poshtë:

E gjithë drejtkëndëshi i errët është indeksi. Katërkuqe e majtë brenda tij është shard primar, i pari në indeks. Ndërsa katërkuqe blu është shard replika. Ato ndodhen në qendra të ndryshme të të dhënave.
Kur ne shtojmë një shard tjetër, ai shkon në qendrën e tretë të të dhënave. Dhe, përfundimisht, ne marrim një strukturë të tillë, që siguron mundësinë për humbje të DC pa humbje të konsistencës së të dhënave:

Rotacioni i indekseve, dmth krijimi i një indeksi të ri dhe fshirja e atij më të vjetër, e vendosëm të ishte 48 orë (në modelin e përdorimit të indeksit: në 48 orët e fundit kërkohet më shpesh).
Ky interval rotacioni i indekseve është i lidhur me arsyet e mëposhtme:
Kur një kërkesë e kërkimit mbërrin në një nodë të caktuar të të dhënave, nga pikëpamja e performancës është më e favorshme kur pyetet një shard, nëse madhësia e tij është e krahasueshme me madhësinë e hipit të nodës. Kjo lejon që pjesa "e nxehtë" e indeksit të mbetet në hip dhe të qasemi shpejt në të. Kur ka shumë " pjesë të nxehta", atëherë shpejtësia e kërkimit mbi indeks degradon.
Kur një nodë fillon të përballojë një kërkesë të kërkimit në një shard, ajo alokon numrin e fijeve që është e barabartë me numrin e bërthamave të hiperthreaded të makinerisë fizike. Nëse kërkesa e kërkimit prek një numër të madh shardeve, atëherë numri i fijeve rritet proporcionalisht. Kjo reflekton negativisht mbi shpejtësinë e kërkimit dhe ndikon në indekson e të dhënave të reja.
Për të siguruar latencën e nevojshme për kërkimin, ne vendosëm të përdorim SSD. Për përpunimin e shpejtë të kërkesave, makinat ku ishin vendosur këto konteiner duhet të kishin së paku 56 bërthama. Numri 56 është zgjedhur si një vlerë e mjaftueshme në kushte që përcakton numrin e fijeve që do të prodhojë Elasticsearch gjatë punës. Në Elasitcsearch shumë parametra të grupit të fijeve varen drejtpërdrejt nga numri i bërthamave të disponueshme, e cila ngushtë lidhet me numrin e nevojshëm të nodës në klaster në parimin "më pak bërthama — më shumë nodë".
Si rezultat, mesatarisht çdo shard peshon diku rreth 20 gigabajt, dhe për 1 indeks kemi 360 sharde. Së fundmi, nëse ne i rotatojmë ato çdo 48 orë, atëherë kemi 15 prej tyre. Çdo indeks përmban të dhëna për 2 ditë.
Skemat e shkruajtjes dhe leximit të të dhënave
Le të shohim se si të dhënat shkruhen në këtë sistem.
Supozoni se kemi një kërkesë që vjen nga Graylog në koordinues. Për shembull, ne duam të indeksojmë 2-3 mijë stringje.
Koordinuesi, pas marrjes së kërkesës nga Graylog, pyet masterin: «Në kërkesën për indekson, na ishte specifikuar me saktësi indeksi, por nuk u specifikua në cilin shard duhet shkruar».
Master përgjigjet: «Shkruaj këtë informacion në shard numër 71», pas së cilës ai dërgohet menjëherë në nodën përkatëse të të dhënave, ku ndodhet primary-shard numër 71.
Pas kësaj, logu i transaksioneve replikohet në replica-shard, i cili ndodhet tashmë në një qendër tjetër të të dhënave.

Nga Graylog në koordinatori arrin një kërkesë për kërkim. Koordinatori e redirekton atë nëpërmjet indeksit, ndërsa Elasticsearch distribuon kërkesat midis primary-shard dhe replica-shard sipas parimit round-robin.

Nodet në numër prej 180 përgjigjen në mënyrë të pabarabartë, dhe ndërsa ato përgjigjen, koordinatori grumbullon informacionin që është tashmë «ndezur» në të nga nodet më të shpejta të të dhënave. Pas kësaj, kur informacioni është mbledhur ose është arritur një skadim kërkese, ai ia kthen gjithçka direkt klientit.
I gjithë ky sistem, në mesatare, përpunon kërkesat për kërkim për 48 orët e fundit për 300-400ms, përjashtuar ato kërkesa që kanë wildcard të udhëhequr.
«Lulet» me Elasticsearch: konfigurimi i Java-s

Për të bërë që gjithçka të funksionojë ashtu siç e dëshironim, ne kaluam shumë kohë duke konfiguruar gjëra të ndryshme në klaster.
Pjesa e parë e problemeve të zbuluara kishte të bënte me mënyrën si është parakonfiguruar Java në Elasticsearch në mënyrë standarde.
Problemi i parë
Ne vëzhguam një numër shumë të madh mesazhesh për faktin se në nivelin Lucene, kur punët ngarkohen në sfond, bashkimet e segmenteve Lucene përfundojnë me gabim. Në të njëjtën kohë, në log-e ishte e dukshme se ishte një gabim OutOfMemoryError. Nga telemetria, ne pamë se hapi ishte i lirë, dhe nuk ishte e qartë pse kjo operacion po dështon.
U zbulua se bashkimet e indekseve Lucene ndodhin jashtë hapit. Dhe konteinerët janë ndjeshëm të kufizuar në burimet e harxhuara. Në këto burime hynte vetëm hapi (vlera heap.size ishte afërsisht e barabartë me RAM-in), dhe ndonjë operacion jashtë hapit dështonte me një gabim alokimi memorie, nëse ndonjë arsye nuk po përfshihej në ato ~500MB që mbeteshin deri në limit.
Zgjidhja ishte mjaft triviale: ne rritëm vëllimin e RAM-it të disponueshëm për konteinerin, pas së cilës harrova për atë probleme që kishim.
Problemi i dytë
Pas rreth 4-5 ditësh nga lëshimi i klasterit, ne vëzhguam se nodet e të dhënave filluan të dalin periodikisht nga klasteri dhe të ktheheshin brenda 10-20 sekondash.
Kur filluam të hulumtonim, u zbulua se kjo memorie jashtë hapit në Elasticsearch nuk kontrollohej pothuajse fare. Kur i dhamë konteinerit më shumë memorie, ne fituam mundësinë për të mbushur pool-it të bufereve direkt me informacione të ndryshme, dhe ajo u pastrua vetëm pasi ishte aktivizuar GC i qartë nga Elasticsearch.
Në disa raste, ky operacion ndodhte mjaft ngadalë, dhe gjatë atij kohëi klasteri arrinte të etiketonte këtë nod si të dalë. Ky problem është përshkruar mirë. .
Zgjidhja ishte si vijon: ne kufizuam mundësinë e Java-s për të përdorur pjesën më të madhe të memories jashtë hapit për këto operacione. Ne e kufizuam atë në 16 gigabajt (-XX:MaxDirectMemorySize=16g), duke arritur që GC i qartë të aktivizohej shumë më shpesh dhe të përfundonte shumë më shpejt, duke ndaluar kështu destabilizimin e klasterit.
Problemi i tretë
Nëse mendoni se problemet me «nodet që braktisin klasterin në momentin më të paparashikuar» përfundojnë këtu, jeni të gabuar.
Kur ne konfiguram punën me indekset, ne e ndalëm zgjedhjen tonë në mmapfs për të në shard-at e freskët me segmentim të madh. Kjo ishte një gabim mjaft i madh, sepse gjatë përdorimit të mmapfs skedari mapohet në kujtesën operative dhe pastaj punojmë me skedarin e mapuar. Për këtë arsye ndodhte që kur GC përpiqej të ndalonte thread-et në aplikacion, ne shkonim ngadalë në safepoint, dhe gjatë rrugës aty aplikacioni ndalonte së përgjigjuri në kërkesat e master-it nëse ishte akoma aktiv. Si pasojë, master-i mendonte se nodi nuk ishte më i pranishëm në klaster. Pas kësaj, pas disa sekondash (5-10), garbage collector përfundonte, nodi rinovonte, hynte përsëri në klaster dhe fillonte inicializimin e shard-ve. Të gjitha këto ngjanin shumë me “prodheksionin që meritonim” dhe nuk ishin të përshtatshme për asgjë serioze.
Për të eliminuar një sjellje të tillë, ne së pari kaluam në mjeshtrin standard niofs, dhe më pas, kur nga versionet e peshta Elastic u kaluam në të gjashtat, provuam hybridfs, ku ky problem nuk u riprodhua. Më shumë rreth llojeve të ruajtjes mund të lexoni. .
Problemi i katërt
Më pas kishte edhe një problem shumë interesant, që ne e trajtuam për një periudhë rekord të gjatë. E kapëm atë për 2-3 muaj, sepse nuk ishte fare e qartë se cili ishte modeli i saj.
Herë pas here koordinatoret tanë shkonin në Full GC, zakonisht pasdite rreth orës 14:00, dhe nga aty nuk ktheheshin më. Ndërkohë, kur regjistronim vonesat e GC, kjo dukej ndryshe: gjithçka po shkonte mirë, mirë, mirë dhe pastaj njëherë — gjithçka ishte ndjerë keq.
Në fillim menduam se kishim një përdorues të keq që po dërgonte ndonjë kërkesë që e çonte koordinuesin jashtë funksionit. Ndërsa kaluam shumë kohë në regjistrimin e kërkesave për të kuptuar se çfarë po ndodhte.
Në fund u zbuluan se në momentin që ndonjë përdorues dërgon një kërkesë shumë të madhe, dhe ajo e ndjek një koordinues të veçantë Elasticsearch, disa nodë përgjigjen më ngadalë se të tjerat.
Dhe koha që koordinuesi pret përgjigjet nga të gjitha nodet, ndan në vetvete rezultatet që janë dërguar nga nodet që kanë përgjigjur tashmë. Kjo për GC do të thotë se modelet e përdorimit të heap-it ndryshojnë shumë shpejt. Dhe ai GC që ne po e përdornim, nuk e përballonte këtë detyrë.
E vetmja zgjidhje që gjetëm për të ndryshuar sjelljen e klasës në një situatë të tillë ishte migrimi në JDK13 dhe përdorimi i mbledhësit të mbeturinave Shenandoah. Kjo zgjidhi problemin, dhe koordinuesit tanë nuk ranë përsëri.
Me këtë, problemet me Java përfunduan dhe filluan problemet me kapacitetin prej.
«Farat» me Elasticsearch: kapaciteti

Problemet me kapacitetin do të thotë se klasteri ynë punon me stabilitet, por gjatë pikave të numrit të dokumenteve që po indeksohen dhe në momentet e manovrave, performanca nuk është e mjaftueshme.
Simptoma e parë e hasur: gjatë ndonjë «eksplozimi» në prodhim, kur gjenerohet papritur një numër shumë i madh logesh, në Graylog fillon të shfaqet shpesh gabimi i indeksimit es_rejected_execution.
Kjo ndodhte sepse thread_pool.write.queue në një nodë të dhënash deri në momentin që Elasticsearch mund të përpunojë kërkesën për indeksim dhe të dërgojë informacionin në shard në disqet, për defaktore mund të mbajë në cache vetëm 200 kërkesa. Dhe në për këtë parametër flitet shumë pak. Tregohet vetëm numri maksimal i thread-ëve dhe madhësia e defaktore.
Natyrisht, shkuam të rregullojmë këtë vlerë dhe zbuluam se konkretisht në konfigurimin tonë, mund të mbahen mirë deri në 300 kërkesa, ndërsa vlera më e lartë rrezikon që ne të kthehemi në Full GC.
Për më tepër, sepse këto janë grupe mesazhesh që vijnë brenda një kërkese, duhej gjithashtu të rregullojmë Graylog që ai të shkruajë jo shpesh dhe në grupe të vogla, por në grupe të mëdha ose çdo 3 sekonda, nëse grupi akoma nuk është plot. Në këtë mënyrë, informacioni që ne shkruajmë në Elasticsearch bëhet i disponueshëm jo pas dy sekondash, por pas pesë (gjë që na kënaq), por zvogëlon numrin e riprovimeve që duhet të bëjmë për të dërguar një grup të madh informacioni.
Ky aspekt është veçanërisht i rëndësishëm në momentet kur ndodhin ndodhi të tilla në prodhim dhe na vijnë ankesa nga programuesit dhe testuesit: në momentin që u nevojiten këto loge, ato u jepen shumë ngadalë.
Filluam të shqyrtonim. Nga njëra anë, ishte e qartë se kërkesat e kërkimit dhe ato të indeksimit në thelb po përpunoheshin në të njëjtat makina fizike, dhe kështu mënyrat e rënie do të ishin të pranishme.
Por kjo mund të shmangej pjesërisht duke marrë parasysh se në versionet e gjashta të Elasticsearch kishte një algoritëm që lejonte shpërndarjen e kërkesave midis nodave të dhënash përkatëse jo në mënyrë të rastësishme (kontaineri që merret me indeksimin dhe mban primary-shard mund të jetë shumë i ngarkuar, dhe nuk do të ketë mundësi të përgjigjet shpejt), por të dërgojë këtë kërkesë në një kontenier më pak të ngarkuar me replica-shard, i cili do të përgjigjej dukshëm më shpejt. Me fjalë të tjera, ne erdhëm te use_adaptive_replica_selection: true.
Pamja e leximit fillon kështu:
Kalimi në këtë algoritëm ndihmoi ndjeshëm në përmirësimin e kohës së kërkimit në ato momente kur kishte një fluks të madh logesh për t'u shkruar.

Së fundi, problemi kryesor ishte që të dilte nga data-center pa dhimbje.
Çfarë doja ne nga klasteri menjëherë pas humbjes së lidhjes me një DC:
Nëse aktuali master ndodhet në data-centerin e humbur, ai do të ri-zgjidhet dhe do të kalojë si rol në një nod tjetër në një DC tjetër.
- Mjeshtri do të përjashtojë shpejt të gjitha nodet e padisponueshme nga klasteri.
- Duke u bazuar në ato që kishim mbetur, do të kuptonte shpejt: në data-centerin e humbur kishim këto primary-shard, dhe shpejt do të promovonte replica-shard-et përkatëse në data-centerin e mbetur, dhe ne do të vazhdojmë indeksimin e të dhënave.
- Si rezultat i kësaj, kapaciteti i klasterit për shkrim dhe lexim do të degjenerohej ngadalë, por në përgjithësi gjithçka do të punonte ngadalë, por stabilisht.
- Siç u zbulua, ne dëshironim diçka të tillë:
Si rezultoi, ne donim ndonjë gjë të tillë:

Dëshira jonë rezultoi me këtë:

Si ndodhi kjo?
Gjatë rënies së qendrës së të dhënave, problemi ynë ishte master-i.
Pse?
Problemi qëndron se në master ka një TaskBatcher, i cili është përgjegjës për shpërndarjen e detyrave specifike dhe ngjarjeve në klaster. Çdo dalje e nodës, çdo avancim i shard-it nga replica në primary, çdo detyrë për krijimin e ndonjë shard-i — gjithçka kalon fillimisht në TaskBatcher, ku përpunohen në mënyrë të njëpasnjëshme dhe në një kanal.
Gjatë tërheqjes së një qendre të dhënash, dukej se të gjitha nodet e të dhënave në qendrat e mbijetuara e konsideronin si detyrë të sajin të informonin master-in "ne kemi humbur këto shard-e dhe këto nodet e të dhënave".
Ndërkohë, nodet e mbijetuara të të dhënave i dërgonin gjithë këtë informacion master-it aktual dhe përpiqeshin të prisnin konfirmimin që ai e kishte pranuar. Ata nuk e prisnin këtë, pasi master-i merrte detyra më shpejt se sa mund të përgjigjej. Nodat përsërisnin kërkesat për shkak të kohës së skadimit ndërsa master-i, në atë kohë, as që përpiqej të përgjigjej dhe ishte plotësisht i përfshirë në detyrën e renditjes së kërkesave sipas prioritetit.
Në formën përfundimtare dukej se nodet e të dhënave po e bombardonin master-in deri sa ai shkonte në full GC. Pas kësaj, roli i master-it kalonte në ndonjë nod tjetër, dhe me të ndodhte e njëjta gjë, dhe në fund klasteri shkatërrohej plotësisht.
Kemi bërë matje dhe deri në versionin 6.4.0, ku kjo u rregullua, na mjaftonte të tërhiqnim vetëm 10 nodet e të dhënave nga 360 për të shkatërruar plotësisht klasterin.
Ishte duke u dukur kështu:

Pas versionit 6.4.0, ku ky defekt i tmerrshëm u rregullua, nodet e të dhënave ndaluan të vrasin master-in. Por ai nuk u bë "më i zgjuar" nga kjo. Në veçanti: kur të tërhiqnim 2, 3 ose 10 (çdo numër tjetër përveç një) nodet e të dhënave, master-i merrte një mesazh të parë, i cili thoshte që nodi A kishte dalë dhe përpiqej ta tregonte këtë për nodin B, nodin C, nodin D.
Dhe në këtë moment, mund ta luftojmë këtë vetëm përmes vendosjes së një kohëzgjatjeje për përpjekjet për të treguar informacion për dikë, të barabartë me rreth 20-30 sekonda, dhe kështu menaxhojmë shpejtësinë e daljes së qendrës së të dhënave nga klasteri.
Në parim, kjo përputhet me kërkesat që fillimisht u bënë për produktin përfundimtar në kuadër të projektit, por nga këndvështrimi i "shkencës së pastër" kjo është një defekt. I cili, për fat të mirë, u rregullua me sukses nga zhvilluesit në versionin 7.2.
Kur një nod i caktuar i të dhënave dilte, dukej se ishte më e rëndësishme të shpërndahej informacioni për daljen e tij sesa të tregohej për të gjithë klasterin se në të ishin disa primary-shard (për të promovuar replica-shard-in në një qendër tjetër të të dhënave në primary, dhe aty mund të shkruhej informacioni).
Prandaj, kur gjithçka "ka kaluar", nodet e dalura nuk janë shënuar menjëherë si stale. Në përputhje me këtë, jemi të detyruar të presim derisa të skadojnë të gjitha ping-et për nodet e dalura dhe vetëm atëherë klasteri ynë fillon të tregojë atë që atje, atje dhe atje duhet të vazhdojë të regjistrojë informacion. Më shumë mund të lexoni për këtë .
Në përfundim, operacioni i daljes së qendrës së të dhënave sot na zë rreth 5 minuta në orët e pikut. Për një masë kaq të madhe dhe të ngadaltë, kjo është një përfundim mjaft i mirë.
Në fund arritëm në zgjidhjen e mëposhtme:
- Kemi 360 nodet e të dhënave me disqe 700 gigabajt.
- 60 koordinatorë për routing të trafikut në këto nodet e të dhënave.
- 40 master-a, të cilat na kanë mbetur si një trashëgimi nga versionet para 6.4.0 — për të mbiquajtur daljen e qendrës së të dhënave, ishim psikologjikisht të gatshëm të humbnim disa makina, për të garantuar madje edhe në skenarin më të keq një kuorum master-i.
- Çdo përpjekje për të kombinuar role në një kontejner na përballi me faktin se përfundimisht ndonjë nod do të prisheshin nën ngarkesë.
- Në të gjithë klasterin përdoret heap.size, e cila është 31 gigabajt: çdo përpjekje për të ulur përmasat çonte në faktin se në kërkesat e rënda kërkuese me wildcard, ndonjëherë do të vriste ndonjë nod, ose do të bllokohej breaker-i i qarkut në vetë Elasticsearch.
- Përveç kësaj, për të siguruar performancën e kërkimit, ne përpiqemi të mbajmë numrin e objekteve në klaster sa më të vogël të jetë e mundur, për të përpunuar sa më pak ngjarje në vendin më të ngushtë, i cili doli të ishte master-i.
Në fund të fundit, për monitorimin
Për ta bërë këtë të funksionojë siç e kishim menduar, ne monitorojmë të mëposhtmet:
- Çdo nod i të dhënave raporton në cloud-in tonë që ekziston, dhe se në të gjenden këto shard-e. Kur ne ndalojmë diçka ndokund, klasteri brenda 2-3 sekondave raporton se në qendrën A kemi ndaluar nodën 2, 3, dhe 4 — kjo do të thotë se në qendrat e tjera të të dhënave nuk mund të ndalojmë ato nodet mbi të cilat mbeten shard-e të vetme.
- Duke njohurit mbi sjelljen e mjeshtrit, ne i kushtojmë vëmendje të madhe numrit të detyrave të pritura. Sepse edhe një detyrë e caktuar, nëse nuk përfundon në kohë, teorikisht në një situatë emergjente mund të bëhet shkaku për të cilin nuk do të përfundojë, për shembull, promovimi i replica-shard në primary, duke mos e mundësuar indeksonimin.
- Po ashtu, ne shikojmë me kujdes vonesat e garbage collector, sepse me këtë kemi pasur vështirësi të mëdha gjatë optimizimit.
- Rejdhe për tread, për të kuptuar paraprakisht ku ndodhet "fqija e ngushtë".
- Dhe metrikat standarde, si heap, RAM dhe I/O.
Kur ndërtojmë monitorimin, është e domosdoshme të merret parasysh karakteristikat e Thread Pool në Elasticsearch. përshkruan mundësitë e konfigurimit dhe vlerat e parazgjedhura për kërkimin, indeksonimin, por nuk përmend fare thread_pool.management. Këto threads përpunojnë, për shembull, kërkesat e tipit _cat/shards dhe të tjera të ngjashme, të cilat janë të dobishme për të shkruar monitorimin. Sa më i madh të jetë klasteri, aq më shumë kërkesa të tilla përpunohen në një njësi kohe, dhe thread_pool.management i përmendur më sipër, përveç faktit që nuk është i pranishëm në dokumentacionin zyrtar, është gjithashtu i limituar me 5 threads si parazgjedhje, të cilat shfrytëzohen shumë shpejt, pas të cilave monitorimi ndalon së funksionuari saktë.
Ajo që dëshiroj të them në përfundim: ia dolëm! Ne arritëm t'u ofrojmë programuesve dhe zhvilluesve tanë një mjet që në çdo situatë është në gjendje të ofrojë shpejt dhe saktë informacion mbi gjithçka që ndodh në prodhim.
Po, ishte mjaft e komplikuar, por megjithatë, ne arritëm t'i përshtatim dëshirat tona në produktet ekzistuese, të cilat nuk ishin dashur të patchohet dhe shkruhen përsëri për ne.

Burimi: habr.com
