Zgjerimi i shpejtë i ruajtjes në linjë për mbi 1 miliard përdorues të ChatGPT (Pjesa II)
Si e optimizuam Azure Cosmos DB në platformën tonë të ruajtjes për aplikacione, Habitat, për të përballuar rritjen e paprecedentë.
Të gjitha produktet e OpenAI kërkojnë akses të shpejtë dhe të besueshme te të dhënat, të cilën e ofron platforma jonë e ruajtjes, Habitat. Ajo duhet t’u përgjigjet brenda milisekondave mbi 1 miliard përdoruesve në 40 rajone gjeografike. Infrastruktura jonë u përball me një sfidë të jashtëzakonshme: të mbështeste rritjen shpërthyese dhe rastet e reja të përdorimit, duke vazhduar të përmirësonte besueshmërinë, performancën dhe ritmin e punës së zhvilluesve të produkteve. Për ta zgjidhur këtë sfidë, duhej të rimendonim projektimin dhe funksionimin e platformës sonë të ruajtjes në linjë. I peshonim vazhdimisht kompromiset, sipas kësaj radhe: fillimisht të bëheshim mjaftueshëm të besueshëm për trafikun kritik të produkteve, pastaj mjaftueshëm të shpejtë për përdoruesit në mbarë botën dhe, së fundi, të operonim me zotësi në shkallë masive.
Kjo seri me dy pjesë shpjegon si e zhvilluam Habitat nga një bibliotekë e thjeshtë klienti dhe një bazë të dhënash në një platformë ruajtjeje të shpërndarë globalisht që shërben mbi 500 petabajt të dhëna. Pjesa I u përqendrua tek evoluimi i Habitat nga një klient Python në një shërbim. Ajo trajtoi edhe teknikat që na lejuan ta çonim një shërbim të bazuar në Python shumë përtej asaj që shumëkush do ta konsideronte praktike.
Në këtë postim, Pjesa II, shpjegojmë si e zgjeruam komponentin bazë të ruajtjes: Azure Cosmos DB. Përmes bashkëpunimit të ngushtë me ekipin Azure, arritëm një qasje të zbatueshme për shumë klientë me kontejnerë të bashkëmenaxhuar, me performancë të shkëlqyer leximi në shkallë masive globale.
Figura 01 · Çfarë është Habitat?
Platforma e ruajtjes online
Habitat është platforma e ruajtjes online që ndërtuam, në mënyrë që produktet e OpenAI të kenë qasje të shpejtë dhe të besueshme tek informacioni i nevojshëm.
- Kërkesa
- Përgjigja
- Ndryshimet (CDC)
Teksa kompanitë zgjerohen, ekipet e infrastrukturës shpesh kalojnë nga administrimi i sistemeve me një klient në sisteme me shumë klientë. Në sistemet me një klient, çdo ekip përgjegjës për një pjesë të produktit mban sistemin e vet. Kjo kufizon shtrirjen e dëmit dhe mundëson ndarje të qartë të përgjegjësive dhe izolim të ngarkesave. Me rritjen e ekipeve dhe të pjesëve të produkteve, ky model bëhet i kushtueshëm për t’u mbajtur. Sistemet me një klient e bëjnë çdo ekip produkti përgjegjës për planifikimin e kapacitetit dhe shpesh çojnë në rezervim burimesh shumë përtej nevojave.
Përkundrazi, sistemet me shumë klientë ia japin kontrollin një ekipi të centralizuar të bazës së të dhënave, me më shumë njohuri dhe përvojë në caktimin e burimeve. Por sistemet me shumë klientë krijojnë problemet e tyre, si ato të fqinjëve problematikë, ku një klient konsumon një pjesë jashtëzakonisht të madhe të burimeve në dëm të klientëve të tjerë.
Në Habitat, duhej t’i peshonim të gjitha këto kompromise për të projektuar një sistem ruajtjeje të besueshëm dhe efikas në shkallë të gjerë. Sot, Habitat është një shtresë baze të dhënash me shumë klientë për shumë produkte të OpenAI. Por bëmë një rrugëtim rrethor: nga përdorimi i një kontejneri Azure Cosmos DB me shumë klientë, te ngritja e kontejnerëve bazë me një klient, e më pas te rikthimi te kontejneri me shumë klientë si zgjedhje e parazgjedhur. Jemi ende në hapat e parë të historisë sonë me shumë klientë në Habitat: mbështetim një gamë të gjerë rastesh përdorimi, por kemi mundur ta shtyjmë investimin në këtë fushë duke shfrytëzuar funksionet bazë të integruara të Azure Cosmos DB kudo që është e mundur.
Para se të shpjegojmë rrugëtimin tonë me Azure Cosmos DB, ja disa njohuri bazë:
Një llogari Azure Cosmos DB përcakton një grup kontejnerësh dhe një politikë replikimi
Për çdo kontejner rezervohet një kapacitet i caktuar përpunimi në njësi kërkesash për sekondë (RU/s)
Të dhënat në çdo kontejner ruhen duke u ndarë sipas një çelësi të caktuar ndarjeje logjike, me kufij të dokumentuar të ruajtjes dhe kapacitetit të përpunimit për çdo çelës ndarjeje logjike
Azure Cosmos DB shpërndan çelësat e ndarjeve logjike në një numër më të vogël ndarjesh fizike bazë. Këto i ndan më tej kur vëllimi i ruajtur tejkalon një prag ose kur kontejnerit i duhen më shumë ndarje fizike për të mbajtur kapacitetin e rezervuar të përpunimit
Fillimisht lejonim çdo ngarkesë nga klientët, duke u mbështetur te kufiri i deklaruar prej 10 mijë RU/s për çelës ndarjeje logjike për të frenuar ngarkesën hyrëse. Në fillim përdornim gjithashtu vetëm një kontejner të parazgjedhur Azure Cosmos DB për çdo llogari. Kjo funksionoi mjaft mirë, por doli problematike për disa arsye:
Për shkak të zgjedhjeve të hershme në API, ua lamë klientëve drejtpërdrejt përzgjedhjen e çelësit të ndarjes logjike. Si rezultat, kemi përplasje të shpeshta mes rasteve të ndryshme të përdorimit të produkteve për çelësa ndarjesh të zakonshëm, si user_id ose workspace_id. Meqë këto raste përdorimi ndanin kufijtë e Azure Cosmos DB për të njëjtët çelësa ndarjesh logjike, projektimi kufizonte kapacitetin e përgjithshëm të përpunimit për një përdorues të caktuar.
Një problem i shpeshtë gjatë zgjerimit të Postgres, para kalimit në Habitat dhe Azure Cosmos DB, ishte se shumë kërkesa nga një organizatë ose çelës tepër aktiv — një klient që gjeneronte ngarkesë joproporcionalisht të lartë — mund ta nxirrnin jashtë funksionit të gjithë bazën e të dhënave. Bëmë përpjekje të mëdha të përbashkëta për t’i ruajtur këta çelësa në memorien specifike dhe për të shtuar mekanizma rezervimi të përkohshëm kur të dhënat mungonin në memorien specifike, në mënyrë që ngarkesa e krijuar të mos mbingarkonte bazën e të dhënave.
Figure 02a · Logical partition key limits
Different clients, the same partition key
Ndonëse kufijtë e dokumentuar të madhësisë së të dhënave dhe kapacitetit të përpunimit vlejnë për çelësat e ndarjeve logjike, në fakt kufijtë zbatohen te ndarja fizike. Në praktikë, kjo do të thotë se ndarjet logjike nuk arrijnë dot 10 000 RU/s. Përkundrazi, ato ndajnë kufijtë e ndarjes fizike me çdo çelës tjetër ndarjeje logjike të vendosur në të njëjtën ndarje fizike.
Kjo u lejonte fqinjëve problematikë të ndikonin te shumë çelësa ndarjesh logjike që nuk kishin lidhje me ta: ngarkesat që punonin me të dhëna për veçori produktesh me përdorim të ngushtë pengonin proceset bazë të hyrjes dhe regjistrimit.
Figure 02b · Noisy neighbors
Different users, the same physical partition
Edhe kufiri i kapacitetit të përpunimit për një ndarje fizike ndryshon, në varësi të kapacitetit total të caktuar për kontejnerin Azure Cosmos DB. Kapaciteti i përpunimit i rezervuar për kontejnerin shpërndahet afërsisht në mënyrë të barabartë mes ndarjeve fizike të tij.
Me rritjen e vëllimit të të dhënave, ndarjet fizike ndahen më tej, duke rritur numrin total të ndarjeve, ndërsa kapaciteti total i rezervuar i përpunimit mbetet i pandryshuar. Si rezultat, kufiri efektiv i kapacitetit të përpunimit për ndarje zvogëlohet ndërsa madhësia e të dhënave rritet.
Për rastet tona me të dhëna të ngjashme me blob-et, që kërkojnë më shumë ruajtje, kjo krijon një lloj dështimi ku vetëm rritja e të dhënave të ruajtura ul kapacitetin e përpunimit për ngarkesat aktive, edhe kur ritmi i kërkesave dhe përdorimi mbeten të qëndrueshëm.
Figure 02C · Weak partitions
The limit falls below demand
A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.
Kontejnerët e veçantë ndihmojnë në zgjidhjen e pjesshme të këtyre kufijve të çelësave të ndarjeve dhe të problemeve me fqinjët. Duke përdorur kontejnerë të veçantë, secilit mund t’i caktohen ndarje fizike të pavarura. Vetëm ngarkesat brenda vetë atij kontejneri mund të bëhen fqinjë problematikë ose të mbivendosen në hapësirën e çelësave të ndarjeve. Nga ana tjetër, ngritja e kontejnerëve të rinj ka kosto shtesë: secili kërkon planifikim të veçantë kapaciteti. Prandaj duam të krijojmë kontejnerë vetëm kur ka kuptim t’i ndajmë sipas shërbimit ose rastit të përdorimit.
Nisëm të përdornim kontejnerë të veçantë Azure Cosmos DB për rastet e reja më kritike që kërkonin izolim të fortë. Duke e kombinuar këtë me një skript që menaxhonte ndarjet e dobëta, duke përshtatur kapacitetin total të përpunimit të rezervuar për çdo kontejner me numrin e ndarjeve të tij fizike, shmangëm në masë të madhe problemet që kishim.
Megjithatë, meqë e kishim nisur me një kontejner të parazgjedhur, shumë raste kritike të trashëguara, për fat të keq, mbetën aty pa një migrim të të dhënave. Për të mbrojtur shërbimet kritike që ende mbështeteshin te të dhënat në kontejnerin e përbashkët të parazgjedhur, shpesh i këshillonim ekipet të krijonin kontejnerë të veçantë për shërbime të reja ose veçori të rëndësishme produktesh. Teksa zgjeroheshim, rritej trysnia mbi kontejnerin e parazgjedhur dhe shtoheshin incidentet në mjedisin e prodhimit. Nisëm të ngrinim kontejnerë për çdo shërbim të ri ose veçori të madhe produkti, vetëm për ta mbrojtur kontejnerin e parazgjedhur nga ngarkesa shtesë.
Kjo na shpëtoi nga shumë ndërprerje të të gjithë platformës, duke e kufizuar ndikimin në degradimin ose ndërprerjen e veçorive apo shërbimeve të veçanta. Megjithatë, me kalimin e kohës, kostot shtesë të ngritjes së kontejnerëve të rinj filluan të na rëndonin:
Në kontejnerin e vjetër të përbashkët të parazgjedhur, kalimi i një rasti të ri përdorimi nga 0 QPS në 1 milion QPS vështirë se do ta ndryshonte ndjeshëm përdorimin total. Por në një kontejner të izoluar, një rast i ri përdorimi që kalon nga 0 në 1 milion QPS mund të përfaqësojë një ngarkesë 1000 herë më të madhe se niveli bazë që vinte vetëm nga testimi i brendshëm i produktit.
Me kontejnerët e dedikuar, ekipet tani duhej të kujtoheshin të rezervonin paraprakisht kapacitetin e përpunimit që prisnin t’u nevojitej në lançim. Ekipet e produkteve shpesh i vinin veçoritë në prodhim dhe harronin të rritnin kapacitetin paraprakisht. Kështu, ditën e lançimit përfundonim në mbledhje për incidente të rënda (SEV), duke u përpjekur ta rritnim kapacitetin e kontejnerëve në minutën e fundit.
Përzierja e ngarkesave është një përfitim thelbësor i sistemeve me shumë klientë, të cilin e humbasim në këmbim të izolimit më të mirë me këtë strategji kontejnerësh.
Figure 03 · Lack of stable aggregate growth
The same workload, different headroom
1K RU/s during load testing → 1M RU/s at launch
Me kalimin e kohës, monitorimi i përdorimit të kontejnerëve të dedikuar kërkonte edhe njohuri të hollësishme për produktin, për të ditur kur trafiku do të zhvendosej ose rritej.
Mund të ofrojmë një skript bazë të shtresës së kontrollit për të rritur kapacitetin e përpunimit të rezervuar për çdo kontejner sipas prirjeve të rritjes. Por, pa rritje të qëndrueshme në total, zgjerimi i duhur praktikisht përfshinte çdo ekip produkti në OpenAI në planifikimin e kapacitetit.
Kjo nuk funksionoi me zgjerimin e organizatës, pasi kujdesi që çdo ekip përgjegjës për një shërbim i kushtonte rezervimit të burimeve të Azure Cosmos DB ndryshonte shumë.
Me rritjen e organizatës, këto probleme operative u bënë të vështira për t’u menaxhuar në shkallë më të gjerë. Mungesa e një ekipi të vetëm qendror për planifikimin bëri që shumë ekipe të planifikonin dobët. Si rrjedhojë, u rikthyem drejt një zgjidhjeje me shumë klientë dhe bashkëpunuam ngushtë me ekipin Azure për të zgjidhur problemet fillestare të këtij modeli, me një arkitekturë të përbashkët:
Duke kufizuar fillimisht ritmin e kërkesave për çelësat më aktivë, pengojmë fqinjët problematikë të konsumojnë të gjithë kapacitetin e disponueshëm të përpunimit të një ndarjeje fizike. Kjo ul efektin e fqinjit problematik, ku një çelës tepër aktiv mund të ndikojë të gjithë platformën.
Po kështu, QoS me kategorizim të kërkesave pengon ngarkesat jashtë linje, si futjet masive ose nxjerrjet e të dhënave, të përdorin të gjithë kapacitetin e përpunimit të një ndarjeje fizike. Duke u caktuar përparësi më të ulët kërkesave të këtyre ngarkesave, ritmi i tyre kufizohet i pari. Kështu shmanget kufizimi i kërkesave ndërvepruese me përparësi më të lartë, që u shërbejnë përdoruesve fundorë.
Azure Cosmos DB kishte tashmë një modalitet pa server që do të zgjidhte problemin tonë të ndarjeve të dobëta në modalitetin me kapacitet të rezervuar. Por kishte një mangësi të madhe: zgjerohej vetëm sipas përdorimit të ruajtjes dhe e kufizonte përdorimin e RU-ve në 5 mijë RU/s për ndarje fizike. Kjo do të zgjidhte problemin e ndarjeve të dobëta, por do të na pengonte të zgjeronim rastet e përdorimit që kërkonin shumë RU.
Ekipi Azure Cosmos DB ndërtoi për ne një modalitet të ri, të përmirësuar, pa server. Ai lejonte çdo ndarje fizike të arrinte 10 mijë RU/s dhe shtonte ndarje të mëtejshme sipas përdorimit të RU-ve, krahas atyre sipas përdorimit të ruajtjes. Kjo na lejoi të hiqnim dorë nga monitorimi dhe rritja manuale e kapacitetit të kontejnerëve.
Me këto ndryshime, kemi mundur të rikthehemi te përdorimi i një kontejneri të vetëm të përbashkët. Kjo e ka thjeshtuar ndjeshëm planifikimin paraprak ose të vazhdueshëm të kapacitetit për ekipet e produkteve, duke ruajtur izolimin mes ngarkesave. Në muajt që pasuan nuk kemi pasur asnjë incident lidhur me rezervimin e burimeve ose fqinjët problematikë, pavarësisht përshpejtimit të zhvillimit të produkteve.
Kur kompanitë arrijnë përmasat e OpenAI, shërbimet e menaxhuara bëhen më pak “të menaxhuara”. Shumë ngarkesa dalin jashtë normës së infrastrukturës së ofruesit të shërbimeve në re. Teksa OpenAI u bë një nga përdoruesit më të mëdhenj të Azure Cosmos DB, operimi me sukses kërkoi një model tjetër: teste dhe panele monitorimi të përbashkëta, kanale të drejtpërdrejta mes inxhinierëve dhe përgjegjësi të përbashkët për lloje dështimesh që shfaqen vetëm në shkallën tonë. Sot, llogaria jonë më e madhe Azure Cosmos DB ruan dhjetëra petabajt të dhëna dhe shërben mbi 20 milionë QPS. Me sa dimë, jemi e vetmja kompani që e ka vënë në përdorim Azure Cosmos DB në këtë shkallë.
Në fund të vitit 2024, një ndërprerje rajonale e bëri të qartë pse ishte i nevojshëm ky bashkëpunim. Në atë kohë, një ndërprerje energjie goditi rajonin kryesor Azure për një nga llogaritë tona më të mëdha Azure Cosmos DB. Gjatë kalimit në sistemin rezervë që pasoi, kuptuam se llogarive tona më të mëdha do t’u duheshin disa orë për të kaluar në një rajon dytësor. As ekipi ynë, as ai i Azure Cosmos DB nuk e kishin testuar këtë në shkallën tonë.
Rreth një muaj më vonë, ndërsa i kthenim këto llogari në rajonin fillestar, shkaktuam një tjetër ndërprerje serioze. Një vërshim i njëkohshëm lidhjesh drejt rajonit fillestar mbingarkoi portën hyrëse të Azure Cosmos DB në atë rajon. Një veçanti në mënyrën si klienti Azure Cosmos DB në modalitetin e portës hyrëse trajtonte kalimet në sistemin rezervë bëri që të gjithë klientët të krijonin menjëherë lidhje dhe të dërgonin kërkesa në rajonin fillestar, edhe pse vetëm një pjesë e ndarjeve fizike ishin kthyer atje.
Në çdo ndërprerje, si OpenAI ashtu edhe Azure zbatuan proceset e tyre të menaxhimit të incidenteve, duke identifikuar disa shkaqe rrënjësore dhe duke zbatuar korrigjime. Por këto ndërprerje ishin simptoma të një problemi më të gjerë sistemik në mënyrën si ekipi ynë dhe ai i Azure Cosmos DB operonin dhe testonin. Në fillim, shërbimet e menaxhuara na lejuan të ecnim shpejt dhe të përqendroheshim te objektivat e biznesit. Në shkallë të gjerë, shërbimet e menaxhuara bëhen më pak të menaxhuara dhe kërkojnë integrim të thellë me ofruesin në çdo nivel, nga projektimi deri te operimi.
Sot, ekipet inxhinierike të Habitat dhe Azure monitorojnë së bashku çdo shtresë të Habitat, nga shtresat tona të shërbimeve deri te shtresat fizike të ruajtjes së Azure Cosmos DB. I zbatojmë dhe i testojmë ndryshimet në një llogari Azure Cosmos DB me përmasat e mjedisit të prodhimit, por jashtë tij. I testojmë dhe i përmirësojmë SDK-të së bashku dhe përcaktojmë praktikat më të mira për zgjerimin dhe dimensionimin e llogarive tona Azure Cosmos DB. Inxhinierët tanë komunikojnë drejtpërdrejt përmes Teams dhe kemi krijuar edhe mënyra për të njoftuar urgjentisht njëri-tjetrin pa kaluar nëpër nivelet e mbështetjes.
Gjatë vitit të fundit kemi bërë shumë punë të përbashkët për të përmirësuar aftësinë e shtresës së kontrollit dhe portës hyrëse të Azure Cosmos DB për t’u zgjeruar. Kemi shtuar mbrojtje nga ngarkesa dhe ruajtje në cache të metadatave të ndryshme në portën hyrëse, për të mbrojtur ndarjen e metadatave të Azure Cosmos DB. Kemi ulur trysninë nga proceset tona Python të habitat-service përmes grupimit dhe ripërdorimit më të madh të lidhjeve, kemi vendosur ngarkesa pune në të njëjtin vend kur ka qenë e mundur dhe kemi izoluar ngarkesat kritike nga ato jashtë linje përmes VPC-ve të ndryshme.
Ky nivel bashkëpunimi inxhinierik ka qenë vendimtar për qëndrueshmërinë e Azure Cosmos DB te ne gjatë vitit të fundit. Çdo sistem mjaftueshëm i madh ose kritik kërkon këtë lloj pune në ekip: kapërcimin e ndarjeve të përgjegjësisë dhe bashkëpunimin përtej kufijve organizativë.
Siç përmendëm në Pjesën I, filozofia jonë bazë është: bëje të funksionojë, bëje të shpejtë, bëje të lirë. Së pari besueshmëria, pastaj performanca, pastaj efikasiteti. Habitat ishte bërë infrastrukturë kritike për OpenAI, ndaj përparësia e parë ishte ta bënim të besueshëm. Teksa sistemi u stabilizua në vitin 2025 dhe OpenAI u zgjerua globalisht, vonesa u bë pengesa e radhës për përdoruesit dhe ekipet e produkteve.
Kapacitetet llogaritëse dhe të ruajtjes shpesh ndodheshin në rajone të ndryshme, duke i bërë të pashmangshme kërkesat ndërrajonale.
Figure 04 · Improving performance at a global scale
Global traffic
Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.
Vendndodhjet gjeografike të burimeve llogaritëse dhe të ruajtjes shërbejnë vetëm për ilustrim.
Vonesa ndryshonte shumë në varësi të vendit ku ruheshin të dhënat dhe ku shërbehej kërkesa. Për t’i bërë kërkesat ndaj Habitat të shpejta, zhvilluesit e produkteve mbështeteshin te ruajtja shtesë në memorien specifike nga ana e klientit, grupimi i kërkesave, minimizimi i leximeve dhe shkrimeve në bazën e të dhënave dhe zhvendosja e punës jashtë rrugës kritike kudo që ishte e mundur. Kjo solli disa zgjidhje interesante në projektimin e produkteve, më rezistente ndaj problemeve të bazës së të dhënave, por edhe i ndërlikoi produktet dhe ngadalësoi ciklet e zhvillimit. Pra, nuk përmbushi qëllimin e Habitat: të nxiste zhvillimin e shpejtë të produkteve pa pasur nevojë të njihje hollësitë e bazës së të dhënave.
Kjo ka qenë një nga përparësitë tona kryesore në vitin 2026. Kemi zhvilluar një strategji me disa shtresa për të optimizuar performancën e leximeve, të cilat përbëjnë mbi 90% të kërkesave ndaj Habitat:
Kemi disa llogari Azure Cosmos DB në rajone të ndryshme Azure në mbarë botën për përdoruesit me kërkesa për qëndrimin e të dhënave. Edhe për përdoruesit pa kërkesa të rrepta për qëndrimin e të dhënave, vendosja e të dhënave pranë tyre ua përmirëson përvojën duke ulur vonesën.
Në praktikë, nuk mund ta zbatojmë këtë gjerësisht jashtë rasteve që lidhen me qëndrimin e të dhënave, sepse vendosja kufizohet nga kapaciteti fizik në re. Për shkak të madhësisë së grupeve tona të të dhënave, shumë rajone nuk kanë hapësirën e jashtëzakonshme të ruajtjes që nevojitet për pjesën e tyre përkatëse të trafikut të përdoruesve.
Në rajone me kapacitet të kufizuar të qendrave të të dhënave, energjisë ose ftohjes, ndonjëherë përballemi me një zgjedhje të drejtpërdrejtë: të rezervojmë kapacitet për ruajtje në të njëjtin vend dhe vonesë më të ulët të Habitat, ose ta përdorim atë për burime llogaritëse shtesë që shërbejnë kërkesat dhe t’i drejtojmë kërkesat për ruajtje më larg.
Si rrjedhojë, vendimet për vendosjen shpesh kërkojnë një kompromis mes: A) optimizimit të vonesës për produkte dhe grupe përdoruesish të ndryshëm dhe B) kapacitetit të disponueshëm të ruajtjes dhe llogaritjes.
Për ngarkesat ku vonesa është më kritike, si metadatat e autentikimit që nevojiten për çdo kërkesë, ulim kohën e vajtje-ardhjes (RTT) mes burimeve llogaritëse dhe Habitat duke përdorur llogari Azure Cosmos DB të replikuara gjerësisht në shumë rajone dytësore. Disa llogari replikohen në të 40 rajonet Azure ku shërbejmë trafik; të tjera replikohen në të paktën një rajon për kontinent.
Na është dashur të ndërtojmë në Habitat, më herët nga sa donim, një shtresë lëvizjeje dhe rutimi të të dhënave që funksionon pa ndërhyrjen e klientit, për t’i zhvendosur grupet e të dhënave mes llogarive me topologji të ndryshme replikimi.
Megjithatë, edhe kjo qasje kufizohet nga kapaciteti dhe zbatohet vetëm për disa grupe të dhënash të përzgjedhura me kujdes.
Ngarkesat e Habitat dominohen nga leximet: aplikacionet marrin vazhdimisht cilësime, gjendje dhe veti të tjera. Një pjesë joproporcionalisht e madhe e trafikut vjen nga një grup relativisht i vogël tipesh të dhënash që përdoren shpesh. Kjo e bën sistemin veçanërisht të përshtatshëm për ruajtje të shpërndarë në memorien specifike. Ruajtja në memorien specifike përmirëson performancën në infrastrukturën me një rajon, por përfitimet shtohen kur punohet në disa rajone, ku ajo mund të "fshehë" vonesën ndërrajonale.
Në Habitat kemi integruar një shtresë memorie specifike të shpërndarë të tipit lookaside. Ajo ruan kopje të objekteve dhe lidhjeve të përdorura së fundi në serverë Valkey, të vendosur në infrastrukturën tonë pranë vendit ku përpunohen kërkesat e përdoruesve. Zakonisht, këto memorie specifike përdorin një afat skadimi (TTL) që balancon përqindjen e gjetjeve në cache me vjetërsimin e të dhënave. TTL-të e shkurtra ulin vjetërsimin, por dobësojnë përfitimin e memories specifike, sepse elementet skadojnë shpejt dhe duhen marrë më shpesh nga burimi. TTL-të më të gjata rrisin përqindjen e gjetjeve në memorien specifike, por shërbejnë të dhëna të vjetruara për më gjatë, duke sjellë përvojë të dobët përdorimi dhe sjellje të paparashikueshme të produktit.
Një qasje tjetër është të kryhen shprehimisht operacione zhvlerësimi kur aplikacioni shkruan në të njëjtat të dhëna bazë. Kjo i mban të dhënat në cache shumë më të përditësuara, por mund të jetë e vështirë të zbatohet saktë. Mbeten gjithashtu disa raste të veçanta, si dështimet e pjesshme, që i lënë të dhënat në cache të vjetruara. Vendosjet në shumë rajone i shtojnë këto probleme, me rrjete ndërrajonale më pak të besueshme dhe me garën mes cache dhe replikimit të ruajtjes bazë. Plotësimi i kësaj qasjeje me TTL kufizon vjetërsimin maksimal, por mbart sërish të njëjtin kompromis të TTL-së të përshkruar më sipër.
Kemi zgjedhur një qasje më të përparuar ndaj zhvlerësimit, duke ndjekur shembullin e sistemeve si TAO i Meta. Cache e integruar e Habitat mbështetet te kapja e ndryshimeve të të dhënave (CDC) përmes rrjedhës së ndryshimeve të Azure Cosmos DB. Ajo shpërndan zhvlerësimet globalisht brenda sekondave, duke arritur përqindje të larta gjetjesh në cache dhe vjetërsim të ulët. Një shërbim në infrastrukturën tonë lexon këtë rrjedhë ndryshimesh dhe zhvlerëson të dhënat në cache-t lokale kur përditësohen të dhënat bazë. Kështu, në leximin pasues të dhënat nuk gjenden në cache dhe ajo mbushet me versionin më të fundit të tyre.
E kemi ulur ndjeshëm vonesën edhe duke hequr kostot shtesë të përpunimit brenda vetë shërbimit Habitat: e rishkruam kodin në Rust, i cili ka performancë më të mirë se versioni fillestar në Python.
Së bashku, këto ndryshime e kanë ulur p50 e përgjithshme globale të leximeve nga rreth 120 ms në rreth 10 ms: një përmirësim 12-fish që kur nisëm të përqendroheshim te performanca në fillim të këtij viti.
Figure 05 · Improving performance at a global scale
p50 latency for reads
Three major design changes improved read latency
Ndonëse cache e ka ulur ndjeshëm medianën e vonesës, kërkesat më të ngadalta ende kërkojnë marrjen e të dhënave që mungojnë në cache nga ruajtja bazë, shpesh nga rajone të largëta. Teksa shtohet kapaciteti i disponueshëm dhe përmirësojmë efikasitetin e ruajtjes, planifikojmë të trajtojmë një sfidë më themelore: vendosjen e të dhënave që në fillim pranë vendit nga ku do të përdoren.
CDC e besueshme dhe e zgjerueshme — shpërndarja e ndryshimeve të bazës së të dhënave te sistemet pasuese — është komponent kritik jo vetëm për strategjinë e cache të Habitat. Miliona ndryshime të kapura për sekondë, në mijëra kontejnerë dhe miliona ndarje të tyre, kalojnë nëpër mbi njëqind tema Kafka. Ato mbështesin edhe indekse dytësore me konsistencë eventuale, rrjedha lëvizjeje të të dhënave, analiza jashtë linje dhe veçori të tjera produktesh në kohë reale. Me zgjerimin global të infrastrukturës sonë bazë, ndjekja e ndryshimeve të rreshtave është bërë gjithnjë e më e ndërlikuar. Nëse një klient dëshiron të regjistrojë një funksion që ekzekutohet sa herë ndryshojnë rreshtat e tipit të tij, fillimisht duhet, ndër të tjera, të përcaktojë cilat llogari dhe kontejnerë Cosmos përmbajnë të dhënat e tij, cila instancë e shërbimit CDC ndjek këta kontejnerë në rajonet përkatëse dhe të përshtatë siç duhet kapacitetin e proceseve punëtore të CDC-së, Kafka-s dhe konsumuesit të vet. Platforma jonë CDC synon t’ua fshehë këto hollësi zhvilluesve të produkteve dhe t’u ofrojë një ndërfaqe të thjeshtë: klientët regjistrojnë një funksion që duan të thirret për rreshtat e ndryshuar, ndërsa ne kujdesemi për lidhjet teknike dhe zgjerimin.
Një shtresë e brendshme kontrolli siguron vazhdimisht kapjen e ndryshimeve nga të gjithë kontejnerët e nevojshëm, zgjedh rajonet Cosmos nga ku do të lexohen dhe shpërndan punën me efikasitet mes mijëra proceseve punëtore në disa rajone gjeografike. Përdorimi i rajoneve replikë dhe i leximeve të rrjedhës me përparësi më të ulët mbron trafikun e Habitat të ndjeshëm ndaj vonesës nga ngarkesat e kapjes në sfond. Në një infrastrukturë kaq të madhe ndodhin vazhdimisht ndërprerje të proceseve punëtore, probleme kontejnerësh, gabime në ruajtjen e rezervimeve të përkohshme, konfigurime të pavlefshme dhe dështime në destinacion. E bëmë më rezistent ciklin e jetës së proceseve punëtore CDC dhe trajtimin e rezervimeve të përkohshme, izoluam dështimet mes rrjedhave dhe ndërtuam masa mbrojtëse për ndryshimet e konfigurimit dhe vëniet në përdorim. Përdorim radhë për mesazhet e padorëzueshme, që dështimet e përhershme të dorëzimit të mos shkaktojnë bllokim në krye të radhës. I përballojmë ndërprerjet rajonale duke i kaluar proceset lexuese në rajone alternative Cosmos. Në shkallën tonë, na është dashur madje të ndryshojmë SDK-në CDC të Azure për ta bërë më efikase ruajtjen e pikave të kontrollit, duke i grupuar ato në memorie dhe duke i shkruar në ruajtje vetëm periodikisht.
Megjithëse përdorimi i brendshëm i Azure Cosmos DB në Habitat është i ndërlikuar, vlera e tij ka qenë gjithmonë fshehja e hollësive të infrastrukturës nga zhvilluesit, për të përshpejtuar zhvillimin e produkteve. Platforma jonë CDC ndjek të njëjtin parim.
Një ekip i vogël arriti të mbështeste një platformë ruajtjeje në rritje të shpejtë duke e mbajtur qëllimisht të kufizuar API-në e ruajtjes, duke vazhduar zgjerimin e shërbimit Python dhe duke u dhënë përparësi sfidave inxhinierike më urgjente. U përqendruam fillimisht te besueshmëria për trafikun kritik të produkteve, pastaj te performanca e leximit për përdoruesit në mbarë botën dhe, së fundi, tek efikasiteti operativ në shkallë të gjerë. Kjo qasje mundësoi rritje të shpejtë dhe raste të reja përdorimi, duke përmirësuar besueshmërinë, performancën dhe ritmin e zhvillimit të produkteve.
Për të zgjeruar Habitat dhe ruajtjen e bisedave për miliardin e ardhshëm të përdoruesve, duhet të zgjidhim vështirësinë e replikimit të të dhënave në të gjithë infrastrukturën tonë, në një shkallë edhe më të madhe. Për t’i paraprirë kësaj, po ndërtojmë vetë një sistem të posaçëm ruajtjeje në linjë në shkallë ekzabajti, të optimizuar për tipet voluminoze të të dhënave të Habitat. Ky sistem në zhvillim kombinon bërthamën RocksDB Cloud nga Rockset me replikimin e bazuar në Raft. Ai zbaton të njëjtin model dokumentesh si Azure Cosmos DB, por përdor ruajtje të shkëputur dhe replikim fizik për të ulur kapacitetin e nevojshëm të memories flash, në këmbim të një kufiri maksimal më të ulët QPS.
Nëse të intereson të punosh në nisma të tilla të infrastrukturës së të dhënave në shkallë avangardë, shiko vendet tona të lira të punës.


