Kërko me shpejtësi 1 TB/s

TL;DR: Katër vjet më parë u largova nga Google me një ide për një mjet të ri të monitorimit të serverëve. Ideja ishte të kombinoheshin funksionet zakonisht të izoluara në një shërbim mbledhjes dhe analiza e regjistrave, mbledhja e matjeve, alarmet dhe tabelat e kontrollit. Një nga parimet është se shërbimi duhet të jetë i vërtetë shpejtë, duke i ofruar devops një përvojë të lehtë, interaktive dhe të këndshme. Kjo kërkon përpunimin e grupeve të të dhënave me shumë gigabajt në fraksione të sekondës duke qëndruar brenda buxhetit. Mjetet ekzistuese të menaxhimit të regjistrave janë shpesh të ngadalshëm dhe të ngathët, kështu që ne u përballëm me një sfidë të mirë: dizajnimi i zgjuar i një mjeti për t'u dhënë përdoruesve një përvojë të re.

Ky artikull përshkruan se si ne në Scalyr e zgjidhëm këtë problem duke aplikuar metoda të shkollës së vjetër, një qasje të forcës brutale, duke eliminuar shtresat e panevojshme dhe duke shmangur strukturat komplekse të të dhënave. Ju mund t'i zbatoni këto mësime për problemet tuaja inxhinierike.

Fuqia e Shkollës së Vjetër

Analiza e regjistrave zakonisht fillon me një kërkim: gjeni të gjitha mesazhet që përputhen me një model të caktuar. Në Scalyr, këto janë dhjetëra ose qindra gigabajt shkrime nga shumë serverë. Qasjet moderne, si rregull, përfshijnë ndërtimin e një strukture komplekse të të dhënave të optimizuar për kërkim. Unë sigurisht e kam parë këtë në Google, ku ata janë mjaft të mirë në këtë lloj gjëje. Por ne u vendosëm në një qasje shumë më të ashpër: skanimi linear i shkrimeve. Dhe funksionoi - ne ofrojmë një ndërfaqe të kërkueshme që është urdhra të përmasave më të shpejta se konkurrentët tanë (shih animacionin në fund).

Vështrimi kryesor ishte se procesorët modernë janë me të vërtetë shumë të shpejtë në operacione të thjeshta dhe të drejtpërdrejta. Kjo është e lehtë për t'u humbur në sistemet komplekse, me shumë shtresa që mbështeten në shpejtësinë I/O dhe operacionet e rrjetit, dhe sisteme të tilla janë shumë të zakonshme sot. Pra, ne zhvilluam një dizajn që minimizon shtresat dhe mbeturinat e tepërta. Me shumë procesorë dhe serverë paralelisht, shpejtësia e kërkimit arrin 1 TB për sekondë.

Marrëdhëniet kryesore nga ky artikull:

  • Kërkimi me forcë brutale është një qasje e zbatueshme për zgjidhjen e problemeve të botës reale në shkallë të gjerë.
  • Forca brutale është një teknikë projektimi, jo një zgjidhje pa punë. Si çdo teknikë, ajo është më e përshtatshme për disa probleme se të tjerat dhe mund të zbatohet dobët ose mirë.
  • Forca brutale është veçanërisht e mirë për të arritur të qëndrueshme produktivitetit.
  • Përdorimi efektiv i forcës brutale kërkon optimizimin e kodit dhe aplikimin e burimeve të mjaftueshme në kohën e duhur. Është i përshtatshëm nëse serverët tuaj janë nën ngarkesë të madhe jo-përdoruesi dhe operacionet e përdoruesit mbeten prioritet.
  • Performanca varet nga dizajni i të gjithë sistemit, jo vetëm nga algoritmi i lakut të brendshëm.

(Ky artikull përshkruan kërkimin e të dhënave në memorie. Në shumicën e rasteve, kur një përdorues kryen një kërkim të regjistrave, serverët Scalyr e kanë ruajtur tashmë atë. Artikulli vijues do të diskutojë kërkimin e regjistrave të paketuar. Vlen të njëjtat parime: kodi efikas, forca brutale me burime të mëdha llogaritëse).

Metoda e forcës brutale

Tradicionalisht, një grup i madh të dhënash kërkohet duke përdorur një indeks të fjalëve kyçe. Kur aplikohet në regjistrat e serverit, kjo do të thotë të kërkoni për çdo fjalë unike në regjistër. Për secilën fjalë, duhet të bëni një listë të të gjitha përfshirjeve. Kjo e bën të lehtë gjetjen e të gjitha mesazheve me këtë fjalë, për shembull 'gabim', 'firefox' ose "transaction_16851951" - thjesht shikoni në indeks.

E përdora këtë qasje në Google dhe funksionoi mirë. Por në Scalyr ne i kërkojmë regjistrat byte pas byte.

Pse? Nga një këndvështrim abstrakt algoritmik, indekset e fjalëve kyçe janë shumë më efikase sesa kërkimet me forcë brutale. Megjithatë, ne nuk shesim algoritme, ne shesim performancën. Dhe performanca nuk ka të bëjë vetëm me algoritmet, por edhe me inxhinierinë e sistemeve. Ne duhet të marrim parasysh gjithçka: vëllimin e të dhënave, llojin e kërkimit, harduerin e disponueshëm dhe kontekstin e softuerit. Ne vendosëm që për problemin tonë të veçantë, diçka si 'grep' ishte më e përshtatshme se një indeks.

Indekset janë të shkëlqyera, por ato kanë kufizime. Një fjalë është e lehtë për t'u gjetur. Por kërkimi i mesazheve me fjalë të shumta, si 'googlebot' dhe '404', është shumë më i vështirë. Kërkimi për një frazë si 'përjashtim i pakapur' kërkon një indeks më të rëndë që regjistron jo vetëm të gjitha mesazhet me atë fjalë, por edhe vendndodhjen specifike të fjalës.

Vështirësia e vërtetë vjen kur nuk kërkon fjalë. Le të themi se dëshironi të shihni se sa trafik po vjen nga robotët. Mendimi i parë është të kërkoni në regjistrat për fjalën 'bot'. Kështu do të gjeni disa robotë: Googlebot, Bingbot dhe shumë të tjerë. Por këtu 'bot' nuk është një fjalë, por një pjesë e saj. Nëse kërkojmë 'bot' në indeks, nuk do të gjejmë asnjë postim me fjalën 'Googlebot'. Nëse kontrolloni çdo fjalë në indeks dhe më pas skanoni indeksin për fjalët kyçe të gjetura, kërkimi do të ngadalësohet shumë. Si rezultat, disa programe regjistrash nuk lejojnë kërkime me fjalë ose (në rastin më të mirë) lejojnë sintaksë të veçantë me performancë më të ulët. Ne duam ta shmangim këtë.

Një problem tjetër janë shenjat e pikësimit. Dëshironi të gjeni të gjitha kërkesat nga 50.168.29.7? Po në lidhje me korrigjimin e regjistrave që përmbajnë [error]? Nënshkrimet zakonisht i kalojnë shenjat e pikësimit.

Më në fund, inxhinierët i duan mjetet e fuqishme dhe ndonjëherë një problem mund të zgjidhet vetëm me një shprehje të rregullt. Indeksi i fjalëve kyçe nuk është shumë i përshtatshëm për këtë.

Përveç kësaj, indekset komplekse. Çdo mesazh duhet të shtohet në disa lista fjalë kyçe. Këto lista duhet të mbahen në një format lehtësisht të kërkueshëm gjatë gjithë kohës. Pyetjet me fraza, fragmente fjalësh ose shprehje të rregullta duhet të përkthehen në operacione me shumë lista, dhe rezultatet të skanohen dhe të kombinohen për të prodhuar një grup rezultatesh. Në kontekstin e një shërbimi në shkallë të gjerë, me shumë qiramarrës, ky kompleksitet krijon probleme të performancës që nuk janë të dukshme kur analizohen algoritmet.

Indekset e fjalëve kyçe gjithashtu marrin shumë hapësirë, dhe ruajtja është një kosto e madhe në një sistem të menaxhimit të regjistrave.

Nga ana tjetër, çdo kërkim mund të konsumojë shumë fuqi kompjuterike. Përdoruesit tanë vlerësojnë kërkimet me shpejtësi të lartë për pyetje unike, por pyetje të tilla bëhen relativisht rrallë. Për pyetjet tipike të kërkimit, për shembull, për një pult, ne përdorim teknika speciale (do t'i përshkruajmë ato në artikullin vijues). Kërkesat e tjera janë mjaft të rralla saqë rrallë duhet të përpunoni më shumë se një në të njëjtën kohë. Por kjo nuk do të thotë se serverët tanë nuk janë të zënë: ata janë të zënë me punën e marrjes, analizimit dhe kompresimit të mesazheve të reja, vlerësimin e sinjalizimeve, kompresimin e të dhënave të vjetra etj. Kështu, ne kemi një furnizim mjaft të konsiderueshëm të procesorëve që mund të përdoren për të ekzekutuar pyetje.

Forca brutale funksionon nëse keni një problem brutal (dhe shumë forcë)

Forca brutale funksionon më mirë në problemet e thjeshta me sythe të vogla të brendshme. Shpesh mund të optimizoni qarkun e brendshëm që të funksionojë me shpejtësi shumë të larta. Nëse kodi është kompleks, është shumë më e vështirë për ta optimizuar atë.

Kodi ynë i kërkimit fillimisht kishte një lak mjaft të madh të brendshëm. Ne ruajmë mesazhe në faqe në 4K; çdo faqe përmban disa mesazhe (në UTF-8) dhe meta të dhëna për çdo mesazh. Metadata është një strukturë që kodon gjatësinë e vlerës, ID-në e mesazhit të brendshëm dhe fusha të tjera. Cikli i kërkimit dukej kështu:

Kërko me shpejtësi 1 TB/s

Ky është një version i thjeshtuar i kodit aktual. Por edhe këtu, vendosjet e shumta të objekteve, kopjet e të dhënave dhe thirrjet e funksioneve janë të dukshme. JVM është mjaft i mirë në optimizimin e thirrjeve të funksioneve dhe shpërndarjen e objekteve kalimtare, kështu që ky kod funksionoi më mirë sesa e meritonim. Gjatë testimit, klientët e përdorën atë me mjaft sukses. Por përfundimisht ne e çuam atë në nivelin tjetër.

(Ju mund të pyesni pse ne i ruajmë mesazhet në këtë format me faqe 4K, tekst dhe metadata, në vend që të punojmë drejtpërdrejt me regjistrat. Ka shumë arsye, të cilat përfundojnë në faktin se nga brenda motori Scalyr është më shumë si një bazë të dhënash e shpërndarë sesa një Sistemi i skedarëve. Kërkimi i tekstit shpesh kombinohet me filtra të stilit DBMS në kufijtë pas analizimit të regjistrave. Ne mund të kërkojmë njëkohësisht mijëra regjistra në të njëjtën kohë dhe skedarët e thjeshtë tekstualë nuk janë të përshtatshëm për menaxhimin tonë të të dhënave transaksionale, të përsëritura dhe të shpërndara).

Fillimisht, dukej se një kod i tillë nuk ishte shumë i përshtatshëm për optimizimin e forcës brutale. "Punë e vërtetë" në String.indexOf() nuk dominonte as profilin e CPU-së. Kjo do të thotë, optimizimi i vetëm kësaj metode nuk do të sillte një efekt të rëndësishëm.

Ndodh që ne ruajmë meta të dhënat në fillim të çdo faqeje dhe teksti i të gjitha mesazheve në UTF-8 paketohet në skajin tjetër. Duke përfituar nga kjo, ne rishkruam qarkun për të kërkuar të gjithë faqen menjëherë:

Kërko me shpejtësi 1 TB/s

Ky version funksionon drejtpërdrejt në pamje raw byte[] dhe kërkon të gjitha mesazhet menjëherë në të gjithë faqen 4K.

Kjo është shumë më e lehtë për t'u optimizuar për metodën e forcës brutale. Cikli i brendshëm i kërkimit thirret njëkohësisht për të gjithë faqen 4K, dhe jo veçmas në çdo postim. Nuk ka kopjim të të dhënave, nuk ka alokim të objekteve. Dhe operacionet më komplekse të meta të dhënave thirren vetëm kur rezultati është pozitiv, dhe jo në çdo mesazh. Në këtë mënyrë ne kemi eliminuar një ton shpenzime të sipërme dhe pjesa tjetër e ngarkesës është e përqendruar në një lak të vogël kërkimi të brendshëm, i cili është i përshtatshëm për optimizim të mëtejshëm.

Algoritmi ynë aktual i kërkimit bazohet në ide e mrekullueshme e Leonid Volnitsky. Është i ngjashëm me algoritmin Boyer-Moore, duke anashkaluar afërsisht gjatësinë e vargut të kërkimit në çdo hap. Dallimi kryesor është se ai kontrollon dy bajt në një kohë për të minimizuar përputhjet e rreme.

Zbatimi ynë kërkon krijimin e një tabele kërkimi 64K për çdo kërkim, por kjo nuk është asgjë në krahasim me gigabajt të të dhënave që po kërkojmë. Laku i brendshëm përpunon disa gigabajt në sekondë në një bërthamë të vetme. Në praktikë, performanca e qëndrueshme është rreth 1,25 GB për sekondë në çdo bërthamë dhe ka vend për përmirësim. Është e mundur të eliminojmë një pjesë të sipërme jashtë ciklit të brendshëm, dhe ne planifikojmë të eksperimentojmë me një lak të brendshëm në C në vend të Java.

Ne përdorim forcë

Ne kemi diskutuar që kërkimi i regjistrave mund të zbatohet "përafërsisht", por sa "fuqi" kemi? Mjaft shumë.

1 bërthamë: Kur përdoret si duhet, një bërthamë e vetme e një procesori modern është mjaft e fuqishme në vetvete.

8 bërthama: Aktualisht po ekzekutojmë në serverët Amazon hi1.4xlarge dhe i2.4xlarge SSD, secili me 8 bërthama (16 threads). Siç u përmend më lart, këto bërthama zakonisht janë të zëna me operacione në sfond. Kur përdoruesi kryen një kërkim, operacionet e sfondit pezullohen, duke liruar të 8 bërthamat për kërkim. Kërkimi zakonisht përfundon në një pjesë të sekondës, pas së cilës puna në sfond rifillon (programi i mbytjes siguron që breshëria e pyetjeve të kërkimit të mos ndërhyjë në punën e rëndësishme të sfondit).

16 bërthama: për besueshmëri, ne organizojmë serverët në grupe master/slave. Çdo master ka një server SSD dhe një EBS nën komandën e tij. Nëse serveri kryesor rrëzohet, serveri SSD menjëherë zë vendin e tij. Pothuajse gjatë gjithë kohës, master dhe slave funksionojnë mirë, kështu që çdo bllok i të dhënave është i kërkueshëm në dy serverë të ndryshëm (serveri slave EBS ka një procesor të dobët, kështu që ne nuk e konsiderojmë atë). Ne e ndajmë detyrën mes tyre, në mënyrë që të kemi në dispozicion gjithsej 16 bërthama.

Shumë bërthama: Në të ardhmen e afërt, ne do të shpërndajmë të dhëna nëpër serverë në mënyrë të tillë që të gjithë të marrin pjesë në përpunimin e çdo kërkese jo të parëndësishme. Çdo bërthamë do të funksionojë. [Shënim: ne zbatuam planin dhe rritëm shpejtësinë e kërkimit në 1 TB/s, shihni shënimin në fund të artikullit].

Thjeshtësia siguron besueshmëri

Një avantazh tjetër i metodës së forcës brutale është performanca e saj mjaft e qëndrueshme. Në mënyrë tipike, kërkimi nuk është shumë i ndjeshëm ndaj detajeve të problemit dhe grupit të të dhënave (mendoj se kjo është arsyeja pse quhet "i trashë").

Indeksi i fjalëve kyçe ndonjëherë prodhon rezultate tepër të shpejta, dhe herë të tjera jo. Le të themi se keni 50 GB regjistra në të cilët termi 'customer_5987235982' shfaqet saktësisht tre herë. Një kërkim për këtë term numëron tre vendndodhje direkt nga indeksi dhe do të përfundojë menjëherë. Por kërkimet komplekse me shkronja të egra mund të skanojnë mijëra fjalë kyçe dhe të marrin një kohë të gjatë.

Nga ana tjetër, kërkimet me forcë brutale kryejnë pak a shumë me të njëjtën shpejtësi për çdo pyetje. Kërkimi i fjalëve të gjata është më i mirë, por edhe kërkimi i një karakteri të vetëm është mjaft i shpejtë.

Thjeshtësia e metodës së forcës brutale do të thotë që performanca e saj është afër maksimumit të saj teorik. Ka më pak opsione për mbingarkesat e papritura të diskut, grindjet e bllokimit, ndjekjen e treguesit dhe mijëra arsye të tjera për dështim. Sapo shikova kërkesat e bëra nga përdoruesit e Scalyr javën e kaluar në serverin tonë më të ngarkuar. Kishte 14 mijë kërkesa. Saktësisht tetë prej tyre u deshën më shumë se një sekondë; 000% e përfunduar brenda 99 milisekondave (nëse nuk keni përdorur mjete të analizës së regjistrave, më besoni: është i shpejtë).

Performanca e qëndrueshme dhe e besueshme është e rëndësishme për lehtësinë e përdorimit të shërbimit. Nëse vonon periodikisht, përdoruesit do ta perceptojnë atë si jo të besueshëm dhe do të ngurrojnë ta përdorin atë.

Kërkimi i regjistrit në veprim

Këtu është një animacion i shkurtër që tregon kërkimin Scalyr në veprim. Ne kemi një llogari demo ku importojmë çdo ngjarje në çdo depo publike Github. Në këtë demonstrim, unë shqyrtoj të dhënat e një jave: afërsisht 600 MB regjistra të papërpunuar.

Videoja u regjistrua drejtpërdrejt, pa përgatitje të veçantë, në desktopin tim (rreth 5000 kilometra nga serveri). Performanca që do të shihni është kryesisht për shkak të optimizimi i klientit në ueb, si dhe një backend të shpejtë dhe të besueshëm. Sa herë që ka një pauzë pa një tregues 'loading', jam unë që ndaloj në mënyrë që të mund të lexoni se çfarë do të shtyp.

Kërko me shpejtësi 1 TB/s

Në përfundim

Kur përpunoni sasi të mëdha të dhënash, është e rëndësishme të zgjidhni një algoritëm të mirë, por "i mirë" nuk do të thotë "i zbukuruar". Mendoni se si kodi juaj do të funksionojë në praktikë. Analiza teorike e algoritmeve lë jashtë disa faktorë që mund të kenë një rëndësi të madhe në botën reale. Algoritmet më të thjeshta janë më të lehta për t'u optimizuar dhe më të qëndrueshme në situata të skajshme.

Mendoni gjithashtu për kontekstin në të cilin kodi do të ekzekutohet. Në rastin tonë, na duhen serverë mjaft të fuqishëm për të menaxhuar detyrat në sfond. Përdoruesit nisin kërkimet relativisht rrallë, kështu që ne mund të huazojmë një grup të tërë serverësh për periudhën e shkurtër të nevojshme për të përfunduar çdo kërkim.

Duke përdorur një metodë të forcës brutale, ne zbatuam një kërkim të shpejtë, të besueshëm dhe fleksibël në një grup regjistrash. Shpresojmë që këto ide të jenë të dobishme për projektet tuaja.

Redakto: Titulli dhe teksti kanë ndryshuar nga "Kërko me 20 GB për sekondë" në "Kërko me 1 TB për sekondë" për të pasqyruar rritjen e performancës gjatë viteve të fundit. Kjo rritje e shpejtësisë është kryesisht për shkak të ndryshimeve në llojin dhe numrin e serverëve EC2 që ne po vendosim sot për t'i shërbyer bazës sonë të rritur të klientëve. Së shpejti do të vijnë ndryshime që do të ofrojnë një rritje tjetër dramatike në efikasitetin operacional dhe ne mezi presim t'i ndajmë ato.

Burimi: www.habr.com

Shto një koment