Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti

Është viti 2019 dhe ne ende nuk kemi një zgjidhje standarde për grumbullimin e regjistrave në Kubernetes. Në këtë artikull, ne dëshirojmë, duke përdorur shembuj nga praktika reale, të ndajmë kërkimet tona, problemet e hasura dhe zgjidhjet e tyre.

Megjithatë, së pari, unë do të bëj një rezervim që klientë të ndryshëm kuptojnë gjëra shumë të ndryshme duke mbledhur shkrime:

  • dikush dëshiron të shohë regjistrat e sigurisë dhe auditimit;
  • dikush - prerje e centralizuar e të gjithë infrastrukturës;
  • dhe për disa, mjafton të mblidhen vetëm regjistrat e aplikacioneve, duke përjashtuar, për shembull, balancuesit.

Më poshtë është prerja më poshtë se si kemi zbatuar "listat e dëshirave" të ndryshme dhe çfarë vështirësish kemi hasur.

Teoria: rreth mjeteve të prerjeve

Sfondi mbi komponentët e një sistemi prerjesh

Regjistrimi ka bërë një rrugë të gjatë, si rezultat i së cilës janë zhvilluar metodologji për mbledhjen dhe analizimin e regjistrave, gjë që ne përdorim sot. Në vitet 1950, Fortran prezantoi një analog të prurjeve standarde hyrëse/dalëse, që e ndihmoi programuesin të korrigjonte programin e tij. Këto ishin regjistrat e parë kompjuterikë që ua lehtësuan jetën programuesve të asaj kohe. Sot ne shohim në to komponentin e parë të sistemit të prerjeve - burimi ose “prodhuesi” i trungjeve.

Shkenca kompjuterike nuk qëndroi në vend: u shfaqën rrjetet kompjuterike, grupimet e para... Sistemet komplekse të përbërë nga disa kompjuterë filluan të funksionojnë. Tani administratorët e sistemit u detyruan të mblidhnin regjistrat nga disa makina dhe në raste të veçanta ata mund të shtonin mesazhe të kernelit OS në rast se duhej të hetonin një dështim të sistemit. Për të përshkruar sistemet e centralizuara të mbledhjes së regjistrave, në fillim të viteve 2000 u publikua RFC3164, i cili standardizoi remote_syslog. Kështu u shfaq një komponent tjetër i rëndësishëm: mbledhës trungjesh dhe ruajtjen e tyre.

Me rritjen e volumit të regjistrave dhe futjen e gjerë të teknologjive në internet, u ngrit pyetja se cilat regjistra duhet t'u tregohen lehtësisht përdoruesve. Veglat e thjeshta të konsolës (awk/sed/grep) janë zëvendësuar nga ato më të avancuara shikuesit e regjistrit - komponenti i tretë.

Për shkak të rritjes së vëllimit të shkrimeve, diçka tjetër u bë e qartë: duhen shkrime, por jo të gjitha. Dhe shkrimet e ndryshme kërkojnë nivele të ndryshme ruajtjeje: disa mund të humbasin brenda një dite, ndërsa të tjerët duhet të ruhen për 5 vjet. Pra, një komponent për filtrimin dhe kursimin e rrjedhave të të dhënave u shtua në sistemin e regjistrimit - le ta quajmë atë filtër.

Storage ka bërë gjithashtu një hap të madh: nga skedarët e rregullt në bazat e të dhënave relacionale dhe më pas në ruajtjen e orientuar drejt dokumenteve (për shembull, Elasticsearch). Pra, depoja u nda nga kolektori.

Në fund të fundit, vetë koncepti i një regjistri është zgjeruar në një lloj rryme abstrakte ngjarjesh që duam t'i ruajmë për historinë. Ose më mirë, në rast se ju duhet të bëni një hetim ose të hartoni një raport analitik...

Si rezultat, në një periudhë relativisht të shkurtër kohe, mbledhja e regjistrave është zhvilluar në një nënsistem të rëndësishëm, i cili me të drejtë mund të quhet një nga nënseksionet në Big Data.

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti
Nëse një herë e një kohë printimet e zakonshme mund të mjaftonin për një "sistem prerjesh", tani situata ka ndryshuar shumë.

Kubernetes dhe shkrimet

Kur Kubernetes erdhi në infrastrukturë, problemi tashmë ekzistues i mbledhjes së shkrimeve nuk e anashkaloi as atë. Në një farë mënyre, ajo u bë edhe më e dhimbshme: menaxhimi i platformës së infrastrukturës ishte jo vetëm i thjeshtuar, por edhe i ndërlikuar në të njëjtën kohë. Shumë shërbime të vjetra kanë filluar të migrojnë në mikroshërbime. Në kontekstin e regjistrave, kjo reflektohet në numrin në rritje të burimeve të regjistrave, ciklin e tyre të veçantë të jetës dhe nevojën për të gjurmuar marrëdhëniet e të gjithë komponentëve të sistemit përmes regjistrave...

Duke parë përpara, mund të them se tani, për fat të keq, nuk ka asnjë opsion të standardizuar të prerjeve për Kubernetes që do të krahasohej në mënyrë të favorshme me të gjithë të tjerët. Skemat më të njohura në komunitet janë si më poshtë:

  • dikush shpalos pirgun EFK (Elasticsearch, Fluentd, Kibana);
  • dikush po provon të lëshuar së fundmi Loki ose përdor Operatori i logimit;
  • ne (dhe ndoshta jo vetëm ne?..) Unë jam kryesisht i kënaqur me zhvillimin tim - shtëpi bari...

Si rregull, ne përdorim paketat e mëposhtme në grupimet K8s (për zgjidhje të vetë-strehuara):

Sidoqoftë, nuk do të ndalem në udhëzimet për instalimin dhe konfigurimin e tyre. Në vend të kësaj, do të fokusohem në mangësitë e tyre dhe në përfundimet më globale për situatën me trungjet në përgjithësi.

Praktikoni me regjistrat në K8

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti

“Regjistrat e përditshëm”, sa prej jush jeni atje?..

Mbledhja e centralizuar e regjistrave nga një infrastrukturë mjaft e madhe kërkon burime të konsiderueshme, të cilat do të shpenzohen për mbledhjen, ruajtjen dhe përpunimin e regjistrave. Gjatë funksionimit të projekteve të ndryshme jemi përballur me kërkesa dhe probleme të ndryshme operacionale që lindin prej tyre.

Le të provojmë ClickHouse

Le të shohim një ruajtje të centralizuar në një projekt me një aplikacion që gjeneron regjistra në mënyrë mjaft aktive: më shumë se 5000 rreshta në sekondë. Le të fillojmë të punojmë me regjistrat e tij, duke i shtuar ato në ClickHouse.

Sapo të kërkohet koha maksimale reale, serveri me 4 bërthama me ClickHouse tashmë do të mbingarkohet në nënsistemin e diskut:

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti

Ky lloj ngarkimi është për faktin se ne po përpiqemi të shkruajmë në ClickHouse sa më shpejt që të jetë e mundur. Dhe baza e të dhënave reagon ndaj kësaj me rritjen e ngarkesës së diskut, e cila mund të shkaktojë gabimet e mëposhtme:

DB::Exception: Too many parts (300). Merges are processing significantly slower than inserts

Fakti është se Tabelat MergeTree në ClickHouse (ato përmbajnë të dhëna log) kanë vështirësitë e tyre gjatë operacioneve të shkrimit. Të dhënat e futura në to gjenerojnë një ndarje të përkohshme, e cila më pas bashkohet me tabelën kryesore. Si rezultat, regjistrimi rezulton të jetë shumë kërkues në disk, dhe gjithashtu i nënshtrohet kufizimit që morëm njoftimin më lart: jo më shumë se 1 nënndarje mund të bashkohen në 300 sekondë (në fakt, kjo është 300 inserte për sekond).

Për të shmangur këtë sjellje, duhet të shkruajë në ClickHouse në copa sa më të mëdha dhe jo më shumë se 1 herë çdo 2 sekonda. Megjithatë, shkrimi me breshëri të mëdha sugjeron që ne duhet të shkruajmë më rrallë në ClickHouse. Kjo, nga ana tjetër, mund të çojë në një tejmbushje buferi dhe humbje të regjistrave. Zgjidhja është rritja e buferit Fluentd, por më pas do të rritet edhe konsumi i memories.

Shënim: Një aspekt tjetër problematik i zgjidhjes sonë me ClickHouse lidhej me faktin se ndarja në rastin tonë (loghouse) zbatohet përmes tabelave të jashtme të lidhura Bashkoni tabelën. Kjo çon në faktin se gjatë kampionimit të intervaleve të mëdha kohore, kërkohet RAM i tepërt, pasi metatable përsëritet nëpër të gjitha ndarjet - madje edhe ato që padyshim nuk përmbajnë të dhënat e nevojshme. Sidoqoftë, tani kjo qasje mund të deklarohet në mënyrë të sigurtë e vjetëruar për versionet aktuale të ClickHouse (c 18.16).

Si rezultat, bëhet e qartë se jo çdo projekt ka burime të mjaftueshme për të mbledhur regjistrat në kohë reale në ClickHouse (më saktë, shpërndarja e tyre nuk do të jetë e përshtatshme). Përveç kësaj, do t'ju duhet të përdorni аккумулятор, të cilit do të kthehemi më vonë. Rasti i përshkruar më sipër është real. Dhe në atë kohë, ne nuk ishim në gjendje të ofronim një zgjidhje të besueshme dhe të qëndrueshme që do t'i përshtatej klientit dhe do të na lejonte të mblidhnim trungje me vonesë minimale...

Po në lidhje me Elasticsearch?

Elasticsearch është i njohur për trajtimin e ngarkesave të rënda të punës. Le ta provojmë në të njëjtin projekt. Tani ngarkesa duket si kjo:

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti

Elasticsearch ishte në gjendje të trette rrjedhën e të dhënave, megjithatë, shkrimi i vëllimeve të tilla në të përdor në masë të madhe CPU-në. Kjo vendoset duke organizuar një grup. Teknikisht, ky nuk është problem, por rezulton se vetëm për të operuar sistemin e mbledhjes së regjistrave ne përdorim tashmë rreth 8 bërthama dhe kemi një komponent shtesë shumë të ngarkuar në sistem...

Përfundimi: ky opsion mund të justifikohet, por vetëm nëse projekti është i madh dhe menaxhimi i tij është i gatshëm të shpenzojë burime të konsiderueshme në një sistem të centralizuar të prerjeve.

Atëherë lind një pyetje e natyrshme:

Cilat regjistra nevojiten vërtet?

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti Le të përpiqemi të ndryshojmë vetë qasjen: regjistrat duhet të jenë njëkohësisht informues dhe jo të mbuluar secili ngjarje në sistem.

Le të themi se kemi një dyqan të suksesshëm në internet. Cilat regjistra janë të rëndësishëm? Të mbledhësh sa më shumë informacion që të jetë e mundur, për shembull, nga një portë pagese, është një ide e shkëlqyer. Por jo të gjitha regjistrat nga shërbimi i prerjes së imazheve në katalogun e produkteve janë kritike për ne: mjaftojnë vetëm gabimet dhe monitorimi i avancuar (për shembull, përqindja e 500 gabimeve që gjeneron ky komponent).

Pra kemi arritur në përfundimin se prerjet e centralizuara nuk janë gjithmonë të justifikuara. Shumë shpesh klienti dëshiron të mbledhë të gjitha regjistrat në një vend, megjithëse në fakt, nga i gjithë regjistri, kërkohet vetëm 5% e kushtëzuar e mesazheve që janë kritike për biznesin:

  • Ndonjëherë mjafton të konfiguroni, të themi, vetëm madhësinë e regjistrit të kontejnerit dhe koleksionistin e gabimeve (për shembull, Sentry).
  • Një njoftim gabimi dhe vetë një regjistër i madh lokal shpesh mund të mjaftojnë për të hetuar incidentet.
  • Ne kishim projekte që mjaftoheshin vetëm me teste funksionale dhe sisteme të mbledhjes së gabimeve. Zhvilluesi nuk kishte nevojë për regjistra si të tillë - ata panë gjithçka nga gjurmët e gabimeve.

Ilustrim nga jeta

Një histori tjetër mund të shërbejë si një shembull i mirë. Ne morëm një kërkesë nga ekipi i sigurisë së një prej klientëve tanë, i cili tashmë po përdorte një zgjidhje komerciale që ishte zhvilluar shumë kohë përpara prezantimit të Kubernetes.

Ishte e nevojshme të "krijosh miq" të sistemit të centralizuar të mbledhjes së regjistrave me sensorin e zbulimit të problemeve të korporatës - QRadar. Ky sistem mund të marrë regjistrat përmes protokollit syslog dhe t'i marrë ato nga FTP. Sidoqoftë, nuk ishte e mundur menjëherë ta integrosh atë me shtojcën remote_syslog për fluentd (siç doli, ne nuk jemi vetëm). Problemet me konfigurimin e QRadar rezultuan të ishin në anën e ekipit të sigurisë së klientit.

Si rezultat, një pjesë e regjistrave kritikë për biznesin u ngarkua në FTP QRadar, dhe pjesa tjetër u ridrejtua përmes syslogut të largët direkt nga nyjet. Madje për këtë kemi shkruar grafik i thjeshtë - ndoshta do të ndihmojë dikë të zgjidhë një problem të ngjashëm... Falë skemës që rezulton, vetë klienti mori dhe analizoi regjistrat kritikë (duke përdorur mjetet e tij të preferuara), dhe ne ishim në gjendje të reduktonim koston e sistemit të prerjeve, duke kursyer vetëm muajin e kaluar.

Një shembull tjetër është mjaft tregues se çfarë nuk duhet bërë. Një nga klientët tanë për përpunim i secilit ngjarjet që vijnë nga përdoruesi, të bëra me shumë linja prodhimi i pastrukturuar informacion në log. Siç mund ta merrni me mend, regjistra të tillë ishin jashtëzakonisht të papërshtatshëm për t'u lexuar dhe ruajtur.

Kriteret për shkrimet

Shembuj të tillë çojnë në përfundimin se përveç zgjedhjes së një sistemi të mbledhjes së regjistrave, ju duhet dizajnoni edhe vetë shkrimet! Cilat janë kërkesat këtu?

  • Regjistrat duhet të jenë në format të lexueshëm nga makina (për shembull, JSON).
  • Regjistrat duhet të jenë kompakt dhe me aftësinë për të ndryshuar shkallën e regjistrimit në mënyrë që të korrigjohen problemet e mundshme. Në të njëjtën kohë, në mjediset e prodhimit ju duhet të përdorni sisteme me një nivel prerjesh si paralajmërim ose gabim.
  • Regjistrat duhet të normalizohen, domethënë, në një objekt log, të gjitha linjat duhet të kenë të njëjtin lloj fushe.

Regjistrat e pastrukturuar mund të çojnë në probleme me ngarkimin e regjistrave në ruajtje dhe një ndalim të plotë të përpunimit të tyre. Si ilustrim, këtu është një shembull me gabimin 400, të cilin shumë e kanë hasur patjetër në regjistrat e rrjedhshëm:

2019-10-29 13:10:43 +0000 [warn]: dump an error event: error_class=Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchError error="400 - Rejected by Elasticsearch"

Gabimi do të thotë që ju po dërgoni një fushë, lloji i së cilës është i paqëndrueshëm në indeks me një hartë të gatshme. Shembulli më i thjeshtë është një fushë në regjistrin e nginx me një ndryshore $upstream_status. Mund të përmbajë ose një numër ose një varg. Për shembull:

{ "ip": "1.2.3.4", "http_user": "-", "request_id": "17ee8a579e833b5ab9843a0aca10b941", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "/staffs/265.png", "protocol": "HTTP/1.1", "status": "200", "body_size": "906", "referrer": "https://example.com/staff", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36", "request_time": "0.001", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "127.0.0.1:9000", "upstream_status": "200", "upstream_response_length": "906", "location": "staff"}
{ "ip": "1.2.3.4", "http_user": "-", "request_id": "47fe42807f2a7d8d5467511d7d553a1b", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "/staff", "protocol": "HTTP/1.1", "status": "200", "body_size": "2984", "referrer": "-", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36", "request_time": "0.010", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "10.100.0.10:9000, 10.100.0.11:9000", "upstream_status": "404, 200", "upstream_response_length": "0, 2984", "location": "staff"}

Regjistrat tregojnë se serveri 10.100.0.10 u përgjigj me një gabim 404 dhe kërkesa u dërgua në një ruajtje tjetër përmbajtjeje. Si rezultat, vlera në regjistra u bë si kjo:

"upstream_response_time": "0.001, 0.007"

Kjo situatë është aq e zakonshme sa që meriton edhe një të veçantë referenca në dokumentacion.

Po në lidhje me besueshmërinë?

Ka raste kur të gjitha shkrimet pa përjashtim janë jetike. Dhe me këtë, skemat tipike të mbledhjes së regjistrave për K8-të e propozuara/diskutuar më sipër kanë probleme.

Për shembull, fluentd nuk mund të mbledhë trungje nga kontejnerët jetëshkurtër. Në një nga projektet tona, kontejneri i migrimit të bazës së të dhënave jetoi për më pak se 4 sekonda dhe më pas u fshi - sipas shënimit përkatës:

"helm.sh/hook-delete-policy": hook-succeeded

Për shkak të kësaj, regjistri i ekzekutimit të migrimit nuk u përfshi në ruajtje. Politika mund të ndihmojë në këtë rast. before-hook-creation.

Një shembull tjetër është rrotullimi i regjistrit të Docker. Le të themi se ekziston një aplikacion që shkruan në mënyrë aktive në regjistrat. Në kushte normale, ne arrijmë të përpunojmë të gjitha regjistrat, por sapo të shfaqet një problem - për shembull, siç përshkruhet më lart me një format të pasaktë - përpunimi ndalon dhe Docker rrotullon skedarin. Rezultati është se regjistrat kritikë të biznesit mund të humbasin.

Kjo është arsyeja pse është e rëndësishme të veçohen rrjedhat e regjistrave, duke futur dërgimin e atyre më të vlefshmet drejtpërdrejt në aplikacion për të garantuar sigurinë e tyre. Përveç kësaj, nuk do të ishte e tepërt të krijoheshin disa "akumulator" i trungjeve, e cila mund t'i mbijetojë mosdisponueshmërisë së shkurtër të ruajtjes gjatë ruajtjes së mesazheve kritike.

Në fund të fundit, nuk duhet ta harrojmë këtë Është e rëndësishme që çdo nënsistem të monitorohet siç duhet. Përndryshe, është e lehtë të hasësh në një situatë në të cilën fluentd është në gjendje CrashLoopBackOff dhe nuk dërgon asgjë, dhe kjo premton humbjen e informacionit të rëndësishëm.

Gjetjet

Në këtë artikull, ne nuk po shikojmë zgjidhjet SaaS si Datadog. Shumë nga problemet e përshkruara këtu janë zgjidhur tashmë në një mënyrë ose në një tjetër nga kompani tregtare të specializuara në mbledhjen e shkrimeve, por jo të gjithë mund të përdorin SaaS për arsye të ndryshme (ato kryesore janë kostoja dhe pajtueshmëria me 152-FZ).

Mbledhja e centralizuar e regjistrave në fillim duket si një detyrë e thjeshtë, por nuk është aspak. Është e rëndësishme të mbani mend se:

  • Vetëm komponentët kritikë duhet të regjistrohen në detaje, ndërsa monitorimi dhe mbledhja e gabimeve mund të konfigurohen për sisteme të tjera.
  • Regjistrimet në prodhim duhet të mbahen minimale në mënyrë që të mos shtohet ngarkesa e panevojshme.
  • Regjistrat duhet të jenë të lexueshëm nga makina, të normalizuara dhe të kenë një format të rreptë.
  • Regjistrat vërtet kritikë duhet të dërgohen në një rrjedhë të veçantë, e cila duhet të ndahet nga ato kryesore.
  • Vlen të merret në konsideratë një akumulator trungu, i cili mund t'ju shpëtojë nga shpërthimet e ngarkesës së lartë dhe ta bëjë ngarkesën në ruajtje më uniforme.

Regjistrimet në Kubernetes (dhe jo vetëm) sot: pritjet dhe realiteti
Këto rregulla të thjeshta, nëse zbatohen kudo, do të lejojnë që qarqet e përshkruara më sipër të funksionojnë - edhe pse atyre u mungojnë komponentë të rëndësishëm (bateria). Nëse nuk i përmbaheni parimeve të tilla, detyra do t'ju çojë lehtësisht ju dhe infrastrukturën drejt një komponenti tjetër të sistemit shumë të ngarkuar (dhe në të njëjtën kohë joefektiv).

PS

Lexoni edhe në blogun tonë:

Burimi: www.habr.com

Shto një koment