
Derisa, në Odnoklassniki, më parë kishte rreth 50 TB të dhënash që procesoheshin në kohë reale, të ruajtura në SQL Server. Për një vëllim të tillë, të sigurosh një qendër të dhënash të shpejtë, të besueshme dhe gjithashtu të qëndrueshme ndaj defekteve, duke përdorur SQL DBMS, është praktikisht e pamundur. Në raste të tilla, zakonisht përdoren një nga depot NoSQL, por jo gjithçka mund të transferohet në NoSQL: disa entitete kërkojnë garanci të transaksioneve ACID.
Kjo na çoi në përdorimin e një depoje NewSQL, që do të thotë një DBMS që ofron qëndrueshmëri, shkallëzim dhe performancë të sistemeve NoSQL, por që ruan garancitë ACID të sistemeve klasike. Ka pak sisteme industriale të këtij klasi të ri që funksionojnë, prandaj ne e realizuam një sistem të tillë vetë dhe e lançuam në operacionin industrial.
Si funksionon dhe çfarë arritëm - lexoni më poshtë.
Sot, audienca mujore e "Odnoklassniki" është mbi 70 milion vizitorë unikë. Ne rrjeteve më të mëdha sociale në botë, dhe në listën e dyzetë të faqeve ku përdoruesit kalojnë më shumë kohë. Infrastrukturat e "OK" përpunojnë ngarkesa shumë të larta: më shumë se një milion kërkesa HTTP/s në frontet. Një pjesë e parkut të serverëve me më shumë se 8000 njësitë janë të vendosura afër njëri-tjetrit - në katër qendrat e të dhënave në Moskë, gjë që lejon sigurimin e një vonese rrjeti më pak se 1 ms midis tyre.
Ne kemi përdorur Cassandra që nga viti 2010, duke filluar nga versioni 0.6. Sot, në funksion janë disa dhjetëra klastera. Klasteri më i shpejtë përpunon më shumë se 4 milion operacione në sekondë, ndërsa më i madhi ruan 260 TB.
Megjithatë, të gjitha këto janë klastere të zakonshme NoSQL, të cilat përdoren për ruajtjen Na duhej të zëvendësonim depozitat kryesore të konsistencës, Microsoft SQL Server, të cilat ishin përdorur që nga fillimi i "Odnoklassniki". Deponi përbëhej nga më shumë se 300 makina SQL Server Standard Edition, të cilat mbanin 50 TB të dhënash - entitete biznesi. Këto të dhëna modifikohen në kuadër të transaksioneve ACID dhe kërkojnë .
Për shpërndarjen e të dhënave midis node-ve SQL Server përdorëm si (shardim). Historikisht, ne kemi përdorur një skemë të thjeshtë të shardimit të të dhënave: çdo entitet i ishte caktuar një token - një funksion nga ID e entitetit. Entitetet me të njëjtin token ishin vendosur në një SQL server. Marrëdhënia e tipit master-detail realizohej në mënyrë që tokenet e regjistrimit kryesor dhe atij të krijuar të ishin gjithmonë identike dhe të ishin në një server. Në rrjetin social, pothuajse të gjitha të dhënat janë krijuar në emër të përdoruesit - domethënë, të gjitha të dhënat e përdoruesit brenda një nënproçesi funksional ruhet në një server. Pra, pothuajse gjithmonë në transaksionet biznesi merrnin pjesë tabela të një SQL serveri, që mundësoi ruajtjen e konsistencës së të dhënave përmes transaksioneve lokale ACID, pa nevojën e përdorimit Falë shardimit dhe për të përshpejtuar punën e SQL:
Nuk përdorim kufizime të çelësit të huaj, pasi me shardimin ID e entitetit mund të ndodhet në një server tjetër.
- Nuk përdorim procedurat e ruajtura dhe trigger-at për shkak të ngarkesës së shtuar në CPU të DBMS.
- Nuk përdorim JOINs për shkak të të gjitha gjërave të mësipërme dhe numrit të madh të leximeve të rastësishme nga disku.
- Jashtë transaksionit, për të reduktuar bllokimet, përdorim nivelin e izolimit të Leximit të Paangazhuar.
- Kryejmë vetëm transaksione të shkurtra (në mesatare më të shkurtra se 100 ms).
- Nuk përdorim UPDATE dhe DELETE të shumë regjistrave për shkak të numrit të madh të bllokimeve - përditësojmë vetëm një regjistër në një kohë.
- Kërkesat gjithmonë i kryejmë vetëm përmes indekseve - një kërkesë me planin e shikimit të plotë të tabelës për ne do të thotë mbingarkesë të DB dhe refuzimin e saj.
- Këto hapa na lejuan të nxjerrim nga SQL-serverat thuajse maksimumin e performancës. Megjithatë, problemet ishin gjithnjë e më të shumta. Le të shikojmë ato.
Problemet me SQL
Duke qenë se ne përdorim shardimin e shkruar vetë, shtimi i shardeve të rinj bëhej manualisht nga administratorët. Gjatë gjithë kësaj kohe, replikat e dhënave të shkallëzuara nuk shërbenin për kërkesat.
- Me rritjen e numrit të regjistrave në tabelë, shpejtësia e futjes dhe modifikimit u ul, kur u shtuan indekse në tabelën ekzistuese, shpejtësia ra shumë herë, krijimi dhe rikrijimi i indekseve ndodhte me downtime.
- Prania e një sasi të vogël Windows për SQL Server në production vështirëson menaxhimin e infrastrukturës.
- Por problemi kryesor -
ĐĐŸ глаĐČĐœĐ°Ń ĐżŃĐŸĐ±Đ»Đ”ĐŒĐ° â
Qëndrueshmëria
Serverat klasik SQL kanë qëndrushmëri të dobët. Supozojmë se keni vetëm një server baze të dhënash, dhe ai dështon çdo tri vjet. Në këtë kohë, faqja e internetit nuk funksionon për 20 minuta, që është e pranueshme. Po sikur të keni 64 servera, faqja nuk funksionon çdo tri javë. Ndërsa nëse keni 200 servera, faqja nuk funksionon çdo javë. Kjo është një problem.
ĂfarĂ« mund tĂ« bĂ«het pĂ«r tĂ« rritur qĂ«ndrushmĂ«rinĂ« e serverit SQL? Wikipedia na propozon tĂ« ndĂ«rtojmĂ« : ku nĂ« rastin e dĂ«shtimit tĂ« ndonjĂ« komponenti ka njĂ« kopje rezerva.
Kjo kërkon një park të shtrenjtë pajisjesh: shumë kopje, fibra optike, ruajtje të përbashkët, dhe madje aktivizimi i rezervës nuk funksionon me besueshmëri: rreth 10% e aktivizimeve përfundojnë me dështimin e njësisë rezervë pas njësisë kryesore.
Por e meta kryesore e një klasteri me disponueshmëri të lartë është se nuk ka disponueshmëri në rast dështimi të qendrës së të dhënave ku ndodhet. 'Odnoklassniki' ka katër qendra të të dhënave, dhe na nevojitet të sigurojmë funksionimin gjatë një katastrofe të plotë në njërën prej tyre.
PĂ«r kĂ«tĂ« ne do tĂ« mund tĂ« aplikonim tĂ« integruar nĂ« SQL Server. Ky zgjidhje Ă«shtĂ« shumĂ« mĂ« e shtrenjtĂ« pĂ«r shkak tĂ« kostos sĂ« softuerit dhe vuajti nga problemet e njohura me replikimin â vonesa tĂ« paparashikueshme tĂ« transaksioneve gjatĂ« replikimit tĂ« sinkronizuar dhe vonesa nĂ« aplikimin e replikimeve (dhe, si pasojĂ«, modifikime tĂ« humbura) gjatĂ« replikimit asinkron. I implicit e bĂ«n kĂ«tĂ« variant plotĂ«sisht tĂ« paaplikueshĂ«m pĂ«r ne.
TĂ« gjitha kĂ«to probleme kĂ«rkonin njĂ« zgjidhje radikale dhe ne filluam analizĂ«n e tyre tĂ« detajuar. KĂ«tu na nevojitet tĂ« njohim se çfarĂ« bĂ«n kryesisht SQL Server â transaksionet.
Transaksioni i thjeshtë
Le të shqyrtojmë një transaksion shumë të thjeshtë, nga këndvështrimi i zhvilluesit të SQL: shtimi i një fotografie në album. Albumet dhe fotografitë ruhen në tavolina të ndryshme. Albumi ka një numërues të fotografive publik. Atëherë ky transaksion ndahet në hapat e mëposhtëm:
- Bllokojmë albumin me çelës.
- Krijojmë një regjistrim në tabelën e fotografive.
- Nëse fotografia ka status publik, përmirësojmë numëruesin e fotografive publike në album, përditësojmë regjistrimin dhe komitojmë transaksionin.
Ose në formën e pseudokodit:
TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(âŠ);
if (photo.status == PUBLIC ) {
album.incPublicPhotosCount();
}
album.update();
TX.commit();Shohim se skenari më i zakonshëm i transaksionit të biznesit është të lexojmë të dhënat nga DB në memorien e serverit të aplikacionit, të ndryshojmë diçka dhe të ruajmë vlerat e reja përsëri në DB. Zakonisht në një transaksion të tillë ne përditësojmë disa entitete, disa tabela.
GjatĂ« kryerjes sĂ« transaksionit, mund tĂ« ndodhin modifikime konkuruese tĂ« tĂ« njĂ«jtave tĂ« dhĂ«na nga njĂ« sistem tjetĂ«r. PĂ«r shembull, Antispami mund tĂ« vendosĂ« se njĂ« pĂ«rdorues Ă«shtĂ« i dyshimtĂ« dhe prandaj tĂ« gjitha fotografitĂ« e pĂ«rdoruesit nuk duhet tĂ« jenĂ« mĂ« publike, ato duhet tĂ« dĂ«rgohen pĂ«r moderim, qĂ« do tĂ« thotĂ« se duhet tĂ« ndryshohet photo.status nĂ« njĂ« vlerĂ« tjetĂ«r dhe tĂ« rregullohen numĂ«ruesit pĂ«rkatĂ«s. ĂshtĂ« e qartĂ« se nĂ«se kjo operacion do tĂ« ndodhte pa garancitĂ« e atomaritetit tĂ« zbatimit dhe izolimit tĂ« modifikimeve konkurente, si nĂ« , rezultati do tĂ« jetĂ« jo ai qĂ« duhet â ose numĂ«ruesi i fotografive do tĂ« tregojĂ« njĂ« vlerĂ« tĂ« pasaktĂ«, ose jo tĂ« gjitha fotografitĂ« do tĂ« dĂ«rgohen pĂ«r moderim.
Një kod i tillë, që manipullon me entitete të ndryshme biznesi brenda një transaksioni, është shkruar shumë gjatë gjithë ekzistencës së Odnoklassniki. Nga përvoja e migrimeve në NoSQL me ne dimë se vështirësitë më të mëdha (dhe shpenzimet kohore) shkaktohen nga nevoja për të zhvilluar kod që siguron konsistencën e të dhënave. Prandaj kërkesa kryesore për ruajtjen e re ishte sigurimi për logjikën aplikative të transaksioneve të vërteta ACID.
Një tjetër, po aq e rëndësishme, kërkesë ishte:
- Në rast dështimi të qendrës së të dhënave duhet të jenë të disponueshme si leximi, ashtu edhe shkruarja në ruajtjen e re.
- Ruajtja e shpejtësisë aktuale të zhvillimit. Kjo do të thotë se gjatë punës me ruajtjen e re, sasia e kodit duhet të jetë afërsisht e njëjtë, nuk duhet të ketë nevojë për të shtuar ndonjë gjë në ruajtje, për të zhvilluar algorithma për zgjidhjen e konflikteve, për mbështetje të indekseve të dyta etj.
- Shpejtësia e punës së ruajtjes së re duhet të jetë mjaft e lartë, si gjatë leximit të të dhënave, ashtu edhe gjatë trajtimit të transaksioneve, që do të thotë që zgjidhjet akademikisht të sakta, universale, por të ngadalta, si për shembull, .
- Automatizimi i shkallëzimit në fluks.
- Përdorimi i serverëve të zakonshëm të lirë, pa nevojën për të blerë pajisje ekzotike.
- Mundësia për të zhvilluar depozitimin me forcat e zhvilluesve të kompanisë. Me fjalë të tjera, prioriteti i ishte dhënë zgjidhjeve të brendshme ose atyre me kod të hapur, për më tepër në Java.
Zgjidhjet, zgjidhjet
Duke analizuar zgjidhjet e mundshme, arritëm në dy mundësi arkitekture:
E para â tĂ« marrim ndonjĂ« SQL-server dhe tĂ« implementojmĂ« qĂ«ndrueshmĂ«rinĂ« e nevojshme, mekanizmin e shkallĂ«zimit, klasterin e qĂ«ndrueshĂ«m, zgjidhjen e konflikteve dhe transaksionet ACID tĂ« shpĂ«rndara, tĂ« besueshme dhe tĂ« shpejta. Ne e vlerĂ«suam kĂ«tĂ« opsion si mjaft tĂ« ndĂ«rlikuar dhe punĂ« tĂ« madhe.
Opsioni i dytĂ« â tĂ« marrim njĂ« depo NoSQL tĂ« gatshme me shkallĂ«zim tĂ« implementuar, klaster tĂ« qĂ«ndrueshĂ«m, zgjidhje konflikti dhe tĂ« realizojmĂ« transaksionet dhe SQL vetĂ«. NĂ« pamje tĂ« parĂ«, madje edhe detyra e realizimit tĂ« SQL, pa pĂ«rmendur transaksionet ACID, duket si njĂ« detyrĂ« pĂ«r vite. Por mĂ« pas kuptuam se grupi i mundĂ«sive SQL qĂ« ne pĂ«rdorim nĂ« praktikĂ« Ă«shtĂ« shumĂ« larg ANSI SQL ashtu si Ă«shtĂ« e largĂ«t nga ANSI SQL. Duke u shqyrtuar mĂ« me vĂ«mendje CQL, kuptuam se Ă«shtĂ« mjaft afĂ«r asaj qĂ« na nevojitet.
Cassandra dhe CQL
Pra, çfarë është interesante për Cassandra, çfarë mundësish ka?
Së pari, mund të krijosh tabela me mbështetje për lloje të ndryshme të të dhënave, mund të bësh SELECT ose UPDATE mbi çelësin primar.
CREATE TABLE photos (id bigint KEY, owner bigint,âŠ);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET ⊠WHERE id=?;PĂ«r tĂ« siguruar koherencĂ«n e tĂ« dhĂ«nave tĂ« replikave, Cassandra pĂ«rdor . NĂ« rastin mĂ« tĂ« thjeshtĂ«, kjo do tĂ« thotĂ« se kur vendosen tre replika tĂ« tĂ« njĂ«jtit rresht nĂ« node tĂ« ndryshme tĂ« klasterit, shkrimi konsiderohet i suksesshĂ«m, nĂ«se shumica e nodeve (dmth dy nga tre) kanĂ« konfirmuar suksesin e kĂ«tij operacioni tĂ« shkrimit. TĂ« dhĂ«nat e rreshtit konsiderohen tĂ« koherentĂ«, nĂ«se gjatĂ« leximit shumica e nodeve janĂ« pyetur dhe kanĂ« konfirmuar ato. NĂ« kĂ«tĂ« mĂ«nyrĂ«, me tre replika garantohet koherenca e plotĂ« dhe e menjĂ«hershme e tĂ« dhĂ«nave nĂ« rastin e dĂ«shtimit tĂ« njĂ« node. Ky qasje na lejoi tĂ« realizojmĂ« njĂ« skemĂ« edhe mĂ« tĂ« besueshme: gjithmonĂ« dĂ«rgojmĂ« kĂ«rkesa nĂ« tĂ« tri replikat, duke pritur pĂ«rgjigjen nga dy mĂ« tĂ« shpejtĂ«. PĂ«rgjigjja e vonuar e tretĂ« nĂ« kĂ«tĂ« rast injorohet. NĂ« kĂ«tĂ« rast, node qĂ« Ă«shtĂ« vonuar me pĂ«rgjigjen mund tĂ« ketĂ« probleme serioze â bllokime, mbledhje plehrash nĂ« JVM, rimarrje e memories direkte nĂ« kernelin linux, dĂ«shtim tĂ« pajisjes, shkĂ«putje nga rrjeti. MegjithatĂ«, kjo nuk ndikon aspak nĂ« operacionin e klientit dhe nĂ« tĂ« dhĂ«na.
Qasja, kur ne i drejtohemi tre nodeve, ndërsa marrim përgjigje nga dy, quhet : kërkesa për replika të tepërta dërgohet para se të 'bjerë'.
NjĂ« tjetĂ«r pĂ«rfitim nga Cassandra Ă«shtĂ« Batchlog â njĂ« mekanizĂ«m qĂ« garanton ose aplikimin e plotĂ«, ose mosaplikimin e plotĂ« tĂ« paketĂ«s sĂ« ndryshimeve qĂ« bĂ«ni. Kjo na lejon tĂ« zgjidhim A nĂ« ACID â atomizimi nga kutia.
Më e afërta me transaksionet në Cassandra është ajo që quhet ''. Por nga transaksionet 'e vërteta' ACID ato janë shumë të largëta: në të vërtetë, është mundësia për të bërë në të dhënat e vetëm një regjistrimi, duke përdorur konsensusin përmes protokollit të rëndë Paxos. Prandaj, shpejtësia e këtyre transaksioneve nuk është shumë e lartë.
ĂfarĂ« na mungoi nĂ« Cassandra
Pra, na duhej të realizonim transaksione të vërteta ACID në Cassandra. Duke përdorur ato, mund të realizonim lehtësisht dy mundësi të tjera të dobishme të DBMS klasike: indekset e shpejta konsistente, që do të na lejonin të bënim kërkesa për të dhëna jo vetëm mbi çelësin primar dhe një gjenerator të zakonshëm të ID auto-incrementale monotone.
C*One
Kështu lindi sistemi i ri i menaxhimit të të dhënave C*One, i përbërë nga tri lloje nodash serverësh:
- Depozitat â serverĂ« (gjashtĂ«) standarde Cassandra, pĂ«rgjegjĂ«s pĂ«r ruajtjen e tĂ« dhĂ«nave nĂ« diskĂ«t lokalĂ«. NdĂ«rsa rritet ngarkesa dhe volumi i tĂ« dhĂ«nave, numri i tyre mund tĂ« shkallĂ«zohet lehtĂ«sisht nĂ« dhjetĂ«ra dhe qindra.
- KoordinatorĂ«t e transaksioneve â sigurojnĂ« zbatimin e transaksioneve.
- KlientĂ«t â serverĂ« aplikacionesh, qĂ« realizojnĂ« operacionet e biznesit dhe nisin transaksionet. Ka mundĂ«si tĂ« jenĂ« mijĂ«ra klientĂ«.

TĂ« gjithĂ« serverĂ«t e llojeve tĂ« ndryshme janĂ« pjesĂ« e njĂ« klasteri tĂ« pĂ«rbashkĂ«t, pĂ«rdorin protokollin e brendshĂ«m tĂ« mesazheve Cassandra pĂ«r tĂ« komunikuar me njĂ«ri-tjetrin dhe pĂ«r shkĂ«mbimin e informacionit tĂ« klasterit. Me ndihmĂ«n e Heartbeat, serverĂ«t mĂ«sojnĂ« pĂ«r dĂ«shtime tĂ« ndĂ«rsjella, mbajnĂ« njĂ« skemĂ« tĂ« pĂ«rbashkĂ«t tĂ« tĂ« dhĂ«nave â tabelat, strukturĂ«n dhe replikimin e tyre; skemĂ«n e ndarjes, topologjinĂ« e klasterit, etj.
Klientët

Në vend të drejtorëve standardë, përdoret modaliteti Fat Client. Kjo nyjë nuk ruan të dhëna, por mund të veprojë si koordinatori për ekzekutimin e kërkesave, dmth. Klienti vetë kryen funksionin e koordinimit të kërkesave të tij: interrogon replikat e magazinës dhe zgjidh konfliktet. Kjo është jo vetëm më e besueshme dhe më e shpejtë se drejtori standard, i cili kërkon komunikim me një koordinator të largët, por gjithashtu lejon menaxhimin e transmetimit të kërkesave. Jashtë një transaksioni të hapur në klient, kërkesat dërgohen në magazina. Në rast se klienti hap një transaksion, të gjitha kërkesat brenda transaksionit dërgohen në koordinatorin e transaksioneve.

Koordinatori i transaksioneve C*One
Koordinatori është ajo që ne e kemi realizuar për C*One nga zero. Ai është përgjegjës për menaxhimin e transaksioneve, bllokimeve dhe rendit të zbatimit të transaksioneve.
PĂ«r çdo transaksion tĂ« shĂ«rbyer, koordinatori gjeneron njĂ« afat tĂ« pĂ«rkohshĂ«m: çdo i ardhshĂ«m Ă«shtĂ« mĂ« i madh se ai i transaksionit tĂ« mĂ«parshĂ«m. Duke qenĂ« se nĂ« Cassandra sistemi i zgjidhjes sĂ« konflikteve bazohet nĂ« afate tĂ« pĂ«rkohshme (nga dy regjistrime konfliktuese, regjistrimi aktual Ă«shtĂ« ai me afatin mĂ« tĂ« vonshĂ«m), konflikti gjithmonĂ« do tĂ« zgjidhet nĂ« favor tĂ« transaksionit tĂ« mĂ«vonshĂ«m. KĂ«shtu e kemi realizuar â njĂ« mĂ«nyrĂ« e lirĂ« pĂ«r tĂ« zgjidhur konfliktet nĂ« njĂ« sistem tĂ« shpĂ«rndarĂ«.
Bllokimet
PĂ«r tĂ« siguruar izolimin, ne vendosĂ«m tĂ« pĂ«rdorim mĂ«nyrĂ«n mĂ« tĂ« thjeshtĂ« â bllokimet pesimiste sipas çelĂ«sit primar tĂ« regjistrimit. NĂ« fjalĂ« tĂ« tjera, nĂ« njĂ« transaksion regjistrimi duhet sĂ« pari tĂ« bllokohet, e mĂ« pas tĂ« lexohen, modifikohen dhe ruhen. VetĂ«m pas njĂ« komitimi tĂ« suksesshĂ«m regjistrimi mund tĂ« ç'bllokohet qĂ« transaksionet konkurruese ta pĂ«rdorin atĂ«.
Realizimi i tillë i bllokimit është i thjeshtë në një mjedis të pa shpërndarë. Në një sistem të shpërndarë ka dy mënyra kryesore: ose të realizosh bllokim të shpërndarë në klaster, ose të shpërndash transaksionet në mënyrë që transaksionet që përfshijnë një regjistrim të shërbehen gjithmonë nga i njëjti koordinator.
Duke qenĂ« se nĂ« rastin tonĂ« tĂ« dhĂ«nat tashmĂ« janĂ« shpĂ«rndarĂ« nĂ« grupe tĂ« transaksioneve lokale nĂ« SQL, vendosĂ«m tĂ« ngelim koordinatoret pĂ«r grupet e transaksioneve lokale: njĂ« koordinator kryen tĂ« gjitha transaksionet me token nga 0 deri nĂ« 9, tjetri â me token nga 10 deri nĂ« 19, dhe kĂ«shtu me radhĂ«. Si rezultat, çdo nga instancat e koordinatoreve bĂ«het master i grupit tĂ« transaksioneve.
Atëherë bllokimet mund të realizohen si një HashMap të zakonshme në memorje të koordinatoreve.
Dështimet e koordinatoreve
Duke qenë se një koordinator shërben vetëm një grup transaksionesh, është shumë e rëndësishme të përcaktohet shpejt fakti i dështimit të tij, në mënyrë që përpjekja për të ekzekutuar transaksionin të qëndrojë brenda afatit. Për ta bërë këtë shpejt dhe besueshëm, ne përdorëm një protokoll të lidhur të kvorumit të boy-kontaktit:
Në çdo qendër të të dhënave vendosen të paktën dy nova koordinatori. Periudhshëm, çdo koordinator dërgon një mesazh të boy-kontaktit tek koordinatoret e tjerë dhe i informon ata për funksionimin e tij, si dhe për mesazhet e boy-kontaktit nga cilët koordinatoret në klaster ai mori më së fundi.

Duke marrë informacion të ngjashëm nga të tjerët në mesazhet e tyre të boy-kontaktit, çdo koordinator vendos për veten se cilat nova të klasterit po funksionojnë dhe cilat jo, duke ndjekur parimin e kvorumit: nëse nova X ka marrë nga shumica e nova në klaster informacion për marrjen normale të mesazheve nga nova Y, atëherë Y funksionon. Dhe anasjelltas, sapo shumica të raportojnë për humbjen e mesazheve nga nova Y, atëherë Y ka dështuar. Curiositet, nëse kvorumi i raporton nova X se nuk merr më mesazhe nga ajo, atëherë edhe nova X do ta konsiderojë veten të dështuar.
Mesazhet e boy-kontaktit dërgohen me një frekuencë të lartë, rreth 20 herë në sekondë, me një periudhë prej 50 ms. Në Java është e vështirë të garantosh reagimin e aplikacionit brenda 50 ms për shkak të ngecjeve të krahasueshme që shkakton mbledhësi i plehrave. Na arriti të arrijmë këtë kohë reagimi duke përdorur mbledhësin e plehrave G1, i cili lejon caktimin e një qëllimi për kohën e ngecjeve të GC. Megjithatë, nganjëherë, mjaft rrallë, ngecjet e mbledhësit kalojnë përtej 50 ms, që mund të çojë në zbulesë të rreme të dështimit. Që të mos ndodhte një e tillë, koordinatori nuk e raporton dështimin e një nova të largët pas humbjes së mesazhit të parë të boy-kontaktit nga ajo, vetëm nëse humbet disa radhazi. Kështu arritëm të arrijmë zbulesën e dështimit të nova të koordinatoreve brenda 200 ms.
Por nuk është vetëm e rëndësishme të kuptohet, cila nova ka ndaluar së funksionuari. Duhet të bëhet diçka me këtë.
Kopjim rezervë
Schema klasike parashikon se në rast dështimi të masterit, të nisë zgjedhjen e një të ri me ndihmën e një nga . Megjithatë, këto algoritme kanë probleme të njohura në lidhje me konvergjencën në kohë dhe gjatësi të procesit të vetëzgjedhjes. Këto vonesa shtesë arritëm t'i shmangim duke përdorur një skemë zëvendësimi për koordinatoret në një rrjet të lidhur plotësisht:

Supozoni se duam tĂ« realizojmĂ« njĂ« transaksion nĂ« grupin 50. Fillimisht do tĂ« pĂ«rcaktojmĂ« skemĂ«n e zĂ«vendĂ«simit, domethĂ«nĂ« cilat node do tĂ« kryejnĂ« transaksionet e grupit 50 nĂ« rastin e dĂ«shtimit tĂ« koordinatores kryesore. QĂ«llimi ynĂ« Ă«shtĂ« tĂ« ruajmĂ« funksionalitetin e sistemit nĂ« rast dĂ«shtimi tĂ« qendrĂ«s sĂ« tĂ« dhĂ«nave. Do tĂ« pĂ«rcaktojmĂ« se rezervi i parĂ« do tĂ« jetĂ« njĂ« node nga njĂ« qendĂ«r tjera e tĂ« dhĂ«nave, ndĂ«rsa rezervi i dytĂ« njĂ« node nga njĂ« qendĂ«r e tretĂ«. Kjo skemĂ« zgjidhet njĂ«herĂ« dhe nuk ndryshon derisa tĂ« ndryshojĂ« topologjia e klasterit, domethĂ«nĂ« derisa tĂ« hyjnĂ« node tĂ« reja (diçka qĂ« ndodh shumĂ« rrallĂ«). Rregulli pĂ«r zgjedhjen e njĂ« masteri tĂ« ri aktiv nĂ« rastin e dĂ«shtimit tĂ« njĂ« tĂ« vjetri do tĂ« jetĂ« gjithmonĂ« ky: masteri aktiv do tĂ« jetĂ« rezervi i parĂ«, dhe nĂ«se edhe ai dĂ«shton â rezervi i dytĂ«.
Kjo skemë është më e besueshme se algoritmi universal, sepse për aktivizimin e një masteri të ri mjafton të përcaktohet fakti i dështimit të atij të vjetër.
Por si do ta dinë klientët se cili nga masterat është aktualisht aktiv? Në 50 ms është e pamundur të shpërndahen informatat për mijëra klientë. Mund të ndodhë që një klient të dërgojë një kërkesë për hapjen e një transaksioni, pa e ditur se ky master tashmë nuk po funksionon, duke e bërë që kërkesa të ngecë në një skadim kohor. Për të parandaluar këtë, klientët dërgojnë spekulativisht një kërkesë për hapjen e transaksionit tek masteri i grupit dhe të dy rezervat e tij, por do të përgjigjet vetëm ai që është master aktiv në atë moment. Të gjitha komunikimet e mëtejshme brenda transaksionit klienti do t'i bëjë vetëm me masterin aktiv.
Masterat rezervë vendosin kërkesat e marra për transaksionet që nuk janë për to në radhë për transaksionet e parakohshme, ku ato ruhen për një periudhë të caktuar. Nëse masteri aktiv vdes, masteri i ri merr në shqyrtim kërkesat për hapjen e transaksioneve nga radhët e tij dhe i përgjigjet klientit. Nëse klienti tashmë ka hapur një transaksion me masterin e vjetër, atëherë përgjigjia e dytë injorohet (dhe, natyrisht, një transaksion i tillë nuk do të përfundojë dhe do të përsëritet nga klienti).
Si funksionon një transaksion
Supozoni se klienti i ka dërguar koordinatores një kërkesë për hapjen e një transaksioni për një aset të tillë me një çelës të tillë. Koordinatori e bllokon këtë aset dhe e vendos në tabelën e bllokimeve në memorie. Nëse është e nevojshme, koordinatori lexon këtë aset nga depoja dhe ruan të dhënat e marra në gjendjen e transaksionit në memorien e koordinatores.

Kur klienti dĂ«shiron tĂ« ndryshojĂ« tĂ« dhĂ«nat nĂ« transaksion, ai e dĂ«rgon njĂ« kĂ«rkesĂ« pĂ«r modifikimin e asetet tek koordinatori, dhe ai vendos tĂ« dhĂ«nat e reja nĂ« tabelĂ«n e gjendjes sĂ« transaksioneve nĂ« memorie. KĂ«shtu, regjistrimi pĂ«rfundon â regjistrimi nĂ« depo nuk bĂ«het.

Kur klienti kërkon të dhënat e veta të ndryshuara brenda një transaksioni aktiv, koordinatori vepron kështu:
- nëse ID është tashmë në transaksion, të dhënat merren nga memoria;
- nëse ID nuk është në memorie, të dhënat e munguar lexohen nga nodet e depove, kombinohen me ato që tashmë janë në memorie, dhe rezultati i dorëzohet klientit.
Kështu, klienti mund të lexojë ndryshimet e veta, ndërsa klientët e tjerë nuk i shohin këto ndryshime, sepse ato ruhen vetëm në memorien e koordinatores, në nodet e Cassandra ato ende nuk ekzistojnë.

Kur klienti dërgon një commit, gjendja, e cila kishte qenë në memorie te shërbimi, ruhet nga koordinatori në logged batch, dhe tashmë në formën e logged batch dërgohet në depot e Cassandra. Depot bëjnë të gjitha nevojat që ky paketë të aplikohet atomikisht (plotësisht) dhe i kthejnë përgjigje koordinatores, e cila pastaj çliron bllokimet dhe konfirmon suksesin e transaksionit tek klienti.

Dhe për të anuluar, koordinatori ka nevojë vetëm të çlirojë memorjen e zënë nga gjendja e transaksionit.
Si rezultat i përmirësimeve të përshkruara më sipër, ne realizuam parimet ACID:
- Atomikësia. Kjo është garancia se asnjë transaksion nuk do të regjistrohet në sistem pjesërisht, do të zbatohet ose të gjitha nënoperacionet e tij, ose asnjëra. Ky princip respektohet nga logged batch në Cassandra.
- Konsistenca. Ădo transaksion i suksesshĂ«m, nga definicioni, regjistron vetĂ«m rezultate tĂ« lejueshme. NĂ«se pas hapjes sĂ« transaksionit dhe kryerjes sĂ« disa operacioneve zbulohet se rezultati nuk Ă«shtĂ« i lejueshĂ«m, herĂ« pas here bĂ«het njĂ« anulim.
- Izolimi. Kur gjatë kryerjes së transaksionit, transaksionet paralele nuk duhet të ndikojnë në rezultatin e tij. Transaksionet konkurruese janë izoluar me anë të bllokimeve pesimiste në koordinatori. Për leximet jashtë transaksionit, respektohet principi i izolimit në nivelin Read Committed.
- QĂ«ndrueshmĂ«ria. PavarĂ«sisht problemeve nĂ« nivelet e poshtme â ndalimi i sistemit, dĂ«shtimi i pajisjeve â ndryshimet e bĂ«ra nga njĂ« transaksion i pĂ«rfunduar me sukses duhet tĂ« mbeten tĂ« ruajtura pas rinisjes sĂ« funksionimit.
Leximi përmes indekseve
Le të marrim një tabelë të thjeshtë:
CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
âŠ)Ajo ka njĂ« ID (çelĂ«si primar), pronar dhe datĂ«n e modificimit. Ne duhet tĂ« bĂ«jmĂ« njĂ« kĂ«rkesĂ« shumĂ« tĂ« thjeshtĂ« â tĂ« zgjedhim tĂ« dhĂ«nat sipas pronarit me datĂ«n e modifikimit "nĂ« 24 orĂ«t e fundit".
SELECT *
WHERE owner=?
AND modified>?Për të bërë një kërkesë të tillë të punojë shpejt, në një DBMS klasik SQL, duhet të ndërtojmë një indeks sipas kolonave (owner, modified). Kështu mund ta bëjmë mjaft lehtë, pasi tani kemi garanci ACID!
Indekset në C*One
Ka një tabelë burimore me fotografi, ku ID e regjistrimit është çelësi primar.

PĂ«r indeksin, C*One krijon njĂ« tabelĂ« tĂ« re, e cila Ă«shtĂ« njĂ« kopje e tĂ« dhĂ«nave burimore. ĂelĂ«si pĂ«rputhet me shprehjen e indeksit, duke pĂ«rfshirĂ« gjithashtu çelĂ«sin primar tĂ« regjistrit nga tabela burimore:

Tani, kërkesa për "pronarin në 24 orët e fundit" mund të riformulohet si një kërkesë nga tabela tjetër:
SELECT * FROM i1_test
WHERE owner=?
AND modified>?Konsistenca e të dhënave në tabelën burimore photos dhe indeksi i1 mbahen automatikisht nga koordinatori. Bazuar vetëm në skemën e të dhënave, kur merr një ndryshim, koordinatori gjeneron dhe ruan jo vetëm ndryshimin e tabelës kryesore, por edhe ndryshimet e kopjave. Nuk kërkohen veprime të tjera me tabelën e indeksit, logjet nuk lexohen, bllokimet nuk përdoren. Kështu që shtimi i indekseve nuk konsumon pothuajse burime dhe nuk ndikon në shpejtësinë e aplikimit të modifikimeve.
Me ndihmën e ACID, arritëm të realizojmë indekse "si në SQL". Ato kanë konsistencë, mund të shkallëzohen, punojnë shpejt, mund të jenë të përbërë dhe të integruar në gjuhën e kërkesave CQL. Për mbështetjen e indekseve nuk është e nevojshme të bëhen ndryshime në kodin aplikativ. E gjithë kjo është e thjeshtë, si në SQL. Dhe ajo që është më e rëndësishmja, indekset nuk ndikojnë në shpejtësinë e ekzekutimit të modifikimeve në tabelën burimore të transaksioneve.
ĂfarĂ« rezultati u arrit
Ne zhvilluam C*One tre vjet më parë dhe e vendosëm në prodhim.
ĂfarĂ« arritĂ«m nĂ« fund? Le tĂ« e vlerĂ«sojmĂ« kĂ«tĂ« nĂ« shembullin e nĂ«nsistemit tĂ« pĂ«rpunimit dhe ruajtjes sĂ« fotografive, njĂ« nga llojet mĂ« tĂ« rĂ«ndĂ«sishme tĂ« tĂ« dhĂ«nave nĂ« rrjetet sociale. Nuk bĂ«het fjalĂ« pĂ«r vetĂ« trupat e fotografive, por pĂ«r tĂ« gjithĂ« metainformacionin. Aktualisht, nĂ« "Odnoklassniki" ka rreth 20 miliardĂ« tĂ« tilla regjistrime, sistemi pĂ«rpunon 80 mijĂ« kĂ«rkesa leximi nĂ« sekondĂ«, deri nĂ« 8 mijĂ« ACID-transaksione nĂ« sekondĂ«, tĂ« lidhura me modifikimin e tĂ« dhĂ«nave.
Kur ne përdorëm SQL me faktor replikimi = 1 (por në RAID 10), metainformacioni i fotografive ruhej në një grup me akses të lartë prej 32 makinash me Microsoft SQL Server (plus 11 të rezervuar). Gjithashtu, u rezervuan 10 servera për ruajtjen e backup-eve. Në total, 50 makina të shtrenjta. Në të njëjtën kohë, sistemi punonte me ngarkesë nominale, pa rezervë.
Pas migrimit nĂ« sistemin e ri, ne morĂ«m faktor replikimi = 3 â njĂ« kopje nĂ« çdo qendĂ«r tĂ« tĂ« dhĂ«nave. Sistemi pĂ«rbĂ«het nga 63 nodet e ruajtjes Cassandra dhe 6 makina koordinatori, nĂ« total 69 servera. Por kĂ«to makina janĂ« shumĂ« mĂ« tĂ« lira, kostoja e tyre e pĂ«rgjithshme pĂ«rbĂ«n rreth 30 % tĂ« kostos sĂ« sistemit nĂ« SQL. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, ngarkesa qĂ«ndron nĂ« nivelin 30 %.
Me implementimin e C*One vonesat gjithashtu u ulĂ«n: nĂ« SQL, operacioni i shkrimit zgjaste rreth 4.5 ms. NĂ« C*One â rreth 1.6 ms. KohĂ«zgjatja e njĂ« transaksioni, nĂ« mesatare, Ă«shtĂ« mĂ« pak se 40 ms, komiti kryhet brenda 2 ms, kohĂ«zgjatja e leximit dhe shkrimit â nĂ« mesatare 2 ms. 99-i percentile Ă«shtĂ« vetĂ«m 3-3.1 ms, numri i kohĂ«ve tĂ« kaluar Ă«shtĂ« ulur 100 herĂ« â gjithçka pĂ«r shkak tĂ« pĂ«rdorimit tĂ« gjerĂ« tĂ« spekulacionit.
Derisa në këtë moment, pjesa e madhe e nodëve SQL Server është hequr nga funksionimi, produktet e reja zhvillohen vetëm me përdorimin e C*One. Ne e kemi adaptuar C*One për të punuar në re , e cila ka lejuar përshpejtimin e krijimit të grupeve të reja, thjeshtimin e konfigurimit dhe automatizimin e operimit. Pa kodin burimor, do të ishte shumë më e vështirë dhe më e komplikuar.
Aktualisht, ne po punojmĂ« pĂ«r tĂ« transferuar ruajtjet tona tĂ« tjera nĂ« re â por kjo Ă«shtĂ« njĂ« histori krejtĂ«sisht tjetĂ«r.
Burimi: habr.com
