
Kuni viimase ajani oli Odnoklassnikis umbes 50 TB andmeid, mida töötleti reaalajas, salvestatud SQL Serverisse. Sellise mahuga on kiire ja usaldusvÀÀrse ning rikkevastase andmekeskuse juurdepÀÀsu tagamine, kasutades SQL andmebaasi, praktiliselt vÔimatu. Tavaliselt kasutatakse sellistes olukordades mÔnd NoSQL-lahendust, kuid mitte kÔik ei sobi NoSQL-i: mÔned entiteedid nÔuavad ACID-tehingute garantiisid.
See viis meid NewSQL-andmebaasi kasutamiseni, mis tĂ€hendab andmebaasi, mis pakub rikkevastupidavust, skaleeritavust ja NoSQL-sĂŒsteemide kiirus, kuid samas sĂ€ilitab klassikaliste sĂŒsteemide jaoks tuttavad ACID-garantii. Töötavad tööstuslikud sĂŒsteemid sellest uuest klassist on haruldased, seetĂ”ttu realiseerisime sellise sĂŒsteemi ise ja lansseerisime selle tööstuslikuks kasutuseks.
Kuidas see töötab ja milline lĂ€henemine Ă”nnestus â loe edasi.
TĂ€na on âOdnoklassnikiâ igakuine kĂŒlastajaskond ĂŒle 70 miljoni unikaalse kĂŒlastaja. Me maailma suurimad sotsiaalmeedia platvormid ja kuulub ka veebi 20 kĂ”ige rohkem kĂŒlastatava saidi hulka. 'OK' infrastruktuur suudab taluda vĂ€ga kĂ”rgeid koormusi: rohkem kui miljon HTTP-pĂ€ringut sekundis. Ăle 8000 serveri jaguneb neljas Moskvas asuvas andmekeskuses, mis vĂ”imaldab tagada vĂ”rgu latentsuse alla 1 ms nende vahel.
Kasutame Cassandrat alates 2010. aastast, alustades versioonist 0.6. TĂ€naseks on kasutuses mitukĂŒmmend klastrit. Kiireim klaster töötleb rohkem kui 4 miljonit operatsiooni sekundis, samas kui suurim salvestab 260 TB.
Kuid need on tavapÀrased NoSQL-klastrid, mida kasutatakse andmete salvestamiseks andmete jaoks. Soovisime asendada peamise kooskÔlastatud andmebaasi, Microsoft SQL Serveri, mida on kasutatud alates 'Odnoklassniki' asutamisest. Andmebaas koosnes enam kui 300 SQL Server Standard Edition masinast, kus oli 50 TB andmeid - Àrikontseptsioone. Need andmed muudetakse ACID-tehingute raames ja vajavad .
SQL Serveri sĂ”lmedes andmete hajutamiseks kasutasime nii vertikaalset kui ka horisontaalset (shardimine). Ajalooliselt oleme kasutanud lihtsat andmete shardimise skeemi: igale entiteedile mÀÀrati token â funktsioon entiteedi ID-st. Ăhised tokenid paigutati ĂŒhele SQL-serverile. Master-detail suhe oli rakendatud nii, et pĂ”hikirje ja alakirje tokenid langevad alati kokku ja asuvad samal serveril. SotsiaalvĂ”rgustikus genereeritakse peaaegu kĂ”ik kirjed kasutaja nime alt â see tĂ€hendab, et kĂ”ik kasutaja andmed ĂŒhe funktsionaalse alamsĂŒsteemi piires salvestatakse ĂŒhele serverile. See tĂ€hendab, et Ă€ritehingutes osalesid peaaegu alati sama SQL-serveri tabelid, mis vĂ”imaldas andmete jĂ€rjepidevust tagada kohalike ACID-tehingute abil, ilma vajaduseta kasutada jaotatud ACID-tehinguid.
Shardimise ja SQL töö kiirusel:
- Mitte kasutada Foreign key constraints, kuna shardimisel vÔib entiteedi ID asuda teisel serveril.
- Me ei kasuta salvestatud protseduure ja trĂŒgeerijaid, kuna need koormavad andmebaasi CPU-d.
- Me ei kasuta JOIN-e eeltoodud pÔhjustel ning paljude juhuslike lugemiste tÔttu kettalt.
- VÀheneme omavaheliste ummikute tagamiseks kasutame vÀljaspool tehingut eraldusastet Read Uncommitted.
- Teostame ainult lĂŒhikesi tehinguid (keskmiselt alla 100 ms).
- Me ei kasuta mitmerealisi UPDATE ja DELETE kĂ€ske, kuna need pĂ”hjustavad palju ummikuid â vĂ€rskendame ainult ĂŒht kirjet korraga.
- KĂŒsimused tĂ€idame alati ainult indeksite kaudu â kĂŒsimus, mille plaan on kogu tabeli vaatamine, tĂ€hendab meie jaoks andmebaasi ĂŒlekoormust ja selle tĂ”rget.
Need sammud on vĂ”imaldanud meie SQL-serveritel saavutada peaaegu maksimaalset jĂ”udlust. Kuid probleeme sai jĂ€rjest rohkem. Vaatame neid ĂŒle.
Probleemid SQL-iga
- Kuna kasutasime kÀsitsi kirjutatud shardingut, lisasid administraatorid uusi shard'e kÀsitsi. Kogu selle aja jooksul ei teenindanud skaleeritavad andmete koopiad pÀringuid.
- Kuna tabelisse kantavate kirjete arv kasvab, vÀheneb sisestamise ja muutmise kiirus, ja indeksite lisamine olemasolevale tabelile kiirus langeb mÀrgatavalt, indeksite loomine ja uuesti loomine toimub katkestustega.
- Piiratud Windowsi olemasolu SQL Serveri jaoks tootmiskeskkonnas raskendab infrastruktuuri haldamist.
Aga peamine probleem on â
Katastroofitaluvus
Klassikalise SQL-serveri katastroofitaluvus on halb. Oletame, et teil on vaid ĂŒks andmebaasi server ja see ebaĂ”nnestub kord kolme aasta jooksul. Sel ajal on veebileht maas 20 minutit, mis on vastuvĂ”etav. Kui teil on 64 serverit, siis on veebileht maas kord kolme nĂ€dala jooksul. Ja kui teil on 200 serverit, siis on veebileht maas iga nĂ€dala. See on probleem.
Mida saab teha SQL-serveri katastroofitaluvuse tĂ”stmiseks? Vikipeedia soovitab meil ĂŒles ehitada : kus ĂŒkskĂ”ik millise komponente ebaĂ”nnestumise korral on duplikatsioon.
See nÔuab kallite seadmete parki: ulatuslikud dubleerimised, kiudoptiline side, jagatud salvestusruum, ja varukoopiate aktiveerimise töökindlus on madal: umbes 10% kÀivitustest lÔppeb varurelva kaaslasena, mis ebaÔnnestub pÔhivÔrguga.
Kuid peamine puudus sellisel kĂ”rge kĂ€ttesaadavuse klastril on nullkĂ€ttesaadavus andmekeskuse tĂ”rke korral, kus see asub. âOdnoklassnikiâ omab nelja andmekeskust, ja peame tagama töökindluse tĂ€ieliku rikke korral ĂŒhes neist.
Selle jaoks vĂ”iks rakendada replikatsiooni, mis on integreeritud SQL Serverisse. See lahendus on palju kallim tarkvara hinna tĂ”ttu ja kannatab hĂ€sti tuntud replikatsiooni probleemide all â ettearvamatud tehingute viivitused sĂŒnkroonses replikatsioonis ja viivitused replikatsioonide rakendamisel (ja seega ka kadunud muudatused) asĂŒnkroonse replikatsiooni puhul. Eeldatav teeb selle variandi meie jaoks tĂ€iesti sobimatuks.
KĂ”ik need probleemid vajasid radikaalset lahendust ning me alustasime nende pĂ”hjalikku analĂŒĂŒsi. Siin peame tutvuma sellega, mis on SQL Serveri peamine ĂŒlesanne â tehingud.
Lihtne tehing
Vaatleme kÔige lihtsamat tehingut, silmas pidades rakenduslikku SQL-programmeerijat: foto lisamine albamisse. Albumid ja fotod salvestatakse erinevatesse tabelitesse. Albumil on avalike fotode arvesti. Seega jaguneb see tehing jÀrgmistesse etappidesse:
- Lukustame albumi vÔtme alusel.
- Loome kirje fotode tabelis.
- Kui fotol on avalik staatus, siis suurendame albumis avalike fotode arvestit, uuendame kirjet ja kinnitame tehingu.
VÔi pseudokoode formaadis:
TX.start("Albumid", id);
Album album = albums.lock(id);
Photo photo = photos.create(âŠ);
if (photo.status == PUBLIC) {
album.incPublicPhotosCount();
}
album.update();
TX.commit();NÀeme, et kÔige levinum Àrilise tehingu stsenaarium on andmete lugemine andmebaasist rakenduste serveri mÀllu, nende muutmine ja uute vÀÀrtuste salvestamine tagasi andmebaasi. Tavaliselt vÀrskendame sellise tehingu kÀigus mitmeid olendeid, mitmeid tabeleid.
Tehingu lĂ€biviimisel vĂ”ib esineda sama andmete konkurentsisĂŒsteemide vahelisi muudatusi. NĂ€iteks vĂ”ib Antispam otsustada, et kasutaja on kahtlane ning seetĂ”ttu ei tohiks kĂ”ik kasutaja fotod enam avalikud olla, need tuleb saata modereerimisele, mis tĂ€hendab, et photo.status tuleb muuta teiseks vÀÀrtuseks ja vastavaid loendureid tuleb reguleerida. Ilmselt, kui see operation toimub ilma atomaarsete rakendamise ja konkureerivate muudatuste isoleerimise garantii, nagu , siis tulemus ei ole see, mis on vajalik â kas fotode loendur nĂ€itab vale vÀÀrtust vĂ”i ei saadeta kĂ”ik fotod modereerimisele.
Sarnast koodi, mis manipuleerib erinevate Ă€riĂŒhendustega ĂŒhe tehingu raames, on kĂ”ikide aastate jooksul Odnoklassnikute olemasolu jooksul kirjutatud vĂ€ga palju. Migratsioonide kogemuse pĂ”hjal NoSQL-le, Teame, et suurimad vĂ€ljakutsed (ja ajakulu) tulenevad vajadusest arendada koodi, mis tagab andmete jĂ€rjepidevuse. SeetĂ”ttu pidasime uue andmesalvestuse peamiseks nĂ”udeks rakendusloogika tĂ”eliste ACID-tehingute toetamise.
Teised, mitte vÀhem olulised nÔuded olid:
- Andmekeskuse tÔrgete korral peavad nii lugemine kui ka kirjutamine olema uude salvestusse saadaval.
- Praeguse arenduskiirus sÀilitamine. See tÀhendab, et uue salvestusega töötades peaks koodi hulk jÀÀma enam-vÀhem samaks, ilma et oleks vaja kirjutada midagi uut salvestusse, vÀlja töötada konfliktide lahendamise algoritme, hooldada teiseseid indekseid jne.
- Uue salvestuse töökiirus peab olema piisavalt kÔrge, nii andmete lugemisel kui tehingute töötlemisel, mis tÔhusalt vÀlistab akadeemiliselt rangeid, universaalseid, kuid aeglaseid lahendusi, nagu nÀiteks .
- Automaatne reaalajas skaleerimine.
- TavapÀraste odavate serverite kasutamine, ilma et oleks vaja osta eksootilisi riistvara.
- Arenduse vÔimalus arendajate poolt. TeisisÔnu, prioriteet anti enda vÔi avatud lÀhtekoodiga lahendustele, eelistatavalt Java-s.
Lahendused, lahendused
AnalĂŒĂŒsides vĂ”imalikke lahendusi, jĂ”udsime kahe arhitektuurivaliku juurde:
Esimene - vĂ”tta ĂŒkskĂ”ik milline SQL-server ja rakendada vajalikud tĂ”rkelevitus, skaleerimismehhanism, tĂ”rkevaba klaster, konfliktide lahendamine ning jaotatud, usaldusvÀÀrsed ja kiire ACID-tehingud. Hindasime seda varianti kui ĂŒsna keerukat ja töömahukat.
Teine variant - vĂ”tta valmis NoSQL-andmehoidla, millel on rakendatud skaleerimine, tĂ”rkevaba klaster, konfliktide lahendamine ning rakendada tehingud ja SQL ise. Esmapilgul tundub isegi SQL-i rakendamise ĂŒlesanne, rÀÀkimata ACID-tehingutest, kui aastatepikkune projekt. Kuid hiljem saime aru, et SQL-i vĂ”imaluste komplekt, mida me praktikas kasutame, on kaugel ANSI SQL-ist, sama kaugel kui ANSI SQL-ist. Kui me vaatame CQL-i veel lĂ€hemalt, saame aru, et see on piisavalt lĂ€hedal sellele, mida me vajame.
Cassandra ja CQL
Nii et, millega Cassandra huvitav on ja milliseid vÔimalusi see pakub?
Esiteks on siin vĂ”imalik luua tabeleid, mis toetavad erinevaid andmetĂŒĂŒpe, ning teha SELECT vĂ”i UPDATE pĂ”hiava pĂ”hjal.
CREATE TABLE photos (id bigint KEY, owner bigint,âŠ);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET ⊠WHERE id=?;Replikatsioonide andmete jĂ€rjepidevuse tagamiseks kasutab Cassandra . Lihtsustatult tĂ€hendab see, et kui kolm koopiat samast rĂŒhmast paiknevad erinevates klastrinode'is, loetakse kirje edukaiks, kui enamus noode (ehk kaks kolmest) on kinnitanud selle kirjutamise operatsiooni edukust. RĂŒhma andmed peetakse kooskĂ”lastatuks, kui lugemise ajal on enamus noode kĂŒsitletud ja kinnitanud need. Seega tagatakse, et kolme koopia olemasolu korral on andmete tĂ€ielik ja kohene kooskĂ”la, kui ĂŒks node kukub. See lĂ€henemine on vĂ”imaldanud meil rakendada veelgi usaldusvÀÀrsemat skeemi: alati saata pĂ€ringud kĂ”ikidele kolmele koopiale, oodates vastust kahest kiirest. Kolmanda koopia viivitatud vastust sellisel juhul ignoreeritakse. Viivitusi kogevatel noodel vĂ”ivad samas olla tĂ”sised probleemid - lag, JVM-is prĂŒgi kogumine, Linuxi kernelis otsemĂ€lu tagasivĂ”tmine, riistvara rike, vĂ”rguĂŒhenduse katkestamine. Siiski ei mĂ”juta see kliendi operatsioone ega andmeid.
LĂ€henemine, kus me pöördume kolme node poole, kuid saame vastuse kahest, nimetatakse : pĂ€ring ĂŒlemÀÀrastele koopiatele saadetakse veel enne, kui need 'langema' hakkavad.
Cassandra ĂŒheks eeliseks on Batchlog â mehhanism, mis tagab kas tĂ€ieliku rakendamise vĂ”i tĂ€ieliku rakendamata jĂ€tmise teie tehtud muudatuste paketis. See vĂ”imaldab meil lahendada A ACID-is â atomaarne nagu vĂ€lja pakutud.
Cassandra kĂ”ige lĂ€hedasem asjaolu tehingutele on nn «« . Kuid nad on âpĂ€risâ ACID-tehingutest kaugel: tegelikult on see vĂ”imalus teha ainult ĂŒhe kirje andmete kohta, kasutades raskema Paxose protokolli konsensust. SeetĂ”ttu on nende tehingute kiirus madal.
Mida me Cassandra'st puudusime
Nii pidime me rakendama Cassandra's tĂ”elist ACID-tehingut. Mille abil saaksime kergesti rakendada kaht muud mugavat vĂ”imalust klassikalistes andmebaasihaldussĂŒsteemides: jĂ€rjepidevad kiireid indekseid, mis vĂ”imaldaksid meil andmete valimist teostada mitte ainult pĂ”hivĂ”tme jĂ€rgi, vaid ka tavalise monotoonse auto-increment ID generaatori.
C*One
Nii sĂŒndis uus andmebaasisĂŒsteem C*One, mis koosneb kolmest tĂŒĂŒpi serveri solgist:
- Andmed â (peaaegu) standardiseeritud Cassandra-serverid, mis vastutavad andmete salvestamise eest kohalikesse diskidesse. Koormuse ja andmemahu suurenedes on nende arvu lihtne skaleerida kĂŒmnete ja sadade kaupa.
- Tehingukoordinaatorid â tagavad tehingute tĂ€itmise.
- Kliendid â rakendusserverid, mis teostavad Ă€ritegevust ja kĂ€ivitavad tehinguid. Selliseid kliente vĂ”ib olla tuhandeid.

KĂ”ik serverid kuuluvad ĂŒldisse klastrisse, kasutavad omavaheliseks suhtlemiseks Cassandra sisemist sĂ”numiprotokolli ja klastriteabe vahetamiseks. Heartbeat'i abil saavad serverid teada ĂŒksteise tĂ”rgetest, sĂ€ilitavad ĂŒhtse andmeskeemi â tabelid, nende struktuur ja replikatsioon; partitsioneerimise skeem, klastrite topoloogia jne.
Kliendid

Standardsete draiverite asemel kasutatakse Fat Client reĆŸiimi. Selline nod ei salvestata andmeid, vaid vĂ”ib toimida pĂ€ringute tĂ€itmise koordinaatorina, st Klient tĂ€idab ise oma pĂ€ringute koordinaatori funktsiooni: kĂŒsib ladustamise koopiaid ja lahendab konfliktid. See on mitte ainult usaldusvÀÀrsem ja kiirem kui standardne draiver, mis nĂ”uab suhtlemist eemal asuva koordinaatoriga, vaid vĂ”imaldab ka pĂ€ringute edastamise juhtimist. Klientide avatud tehingute puhul saadetakse pĂ€ringud ladustamisse. Kui klient on avadanud tehingu, siis suunatakse kĂ”ik selle tehingu pĂ€ringud tehingute koordinaatorisse.

Tehingute koordinaator C*One
Koordinaator on see, mida me oleme C*One jaoks nullist vÀlja ehitanud. Ta vastutab tehingute, lukustuste ja tehingute kehtestamise jÀrjekorra haldamise eest.
Iga teenindatava tehingu jaoks genereerib koordinaator ajatempli: iga jĂ€rgmine on suurem kui eelmise tehingu oma. Kuna Cassandras pĂ”hineb konfliktide lahendamise sĂŒsteem ajatemplitel (kaks konfliktset kirjet loetakse aktuaalseks see, millel on hilisem ajatempli vÀÀrtus), siis lahendatakse konflikt alati jĂ€rgmise tehingu kasuks. Nii oleme me rakendanud â odav viis konfliktide lahendamiseks jaotatud sĂŒsteemis.
Lukud
Isolatsiooni tagamiseks otsustasime kasutada kĂ”ige lihtsamat meetodit â pessimistlikud lukud kirje pĂ”hi vĂ”tme jĂ€rgi. TeisisĂ”nu, tehingu kĂ€igus tuleb kirje esmalt lukustada, enne kui seda saab lugeda, muuta ja salvestada. Ainult pĂ€rast eduka komiteerimist vĂ”ib kirje lukust vabastada, et konkurentsivĂ”imelised tehingud saaksid seda kasutada.
Selle blokeerimise rakendamine on lihtne jaotamata keskkonnas. Jaotatud sĂŒsteemis on kaks peamist teed: kas rakendada jaotatud lukustust klastris vĂ”i jaotada tehingud nii, et ĂŒhe kirje osalusega tehingud teenindatakse alati sama koordinaatori poolt.
Kuna meie juhul on andmed juba jaotatud kohalike tehingute gruppides SQL-is, otsustati mÀÀrata koordinaatoritele kohalike tehingute grupid: ĂŒks koordinaator tĂ€idab kĂ”ik tehingud tokeniga vahemikus 0 kuni 9, teine â vahemikus 10 kuni 19 ja nii edasi. Tulemuseks on see, et iga koordinaatori eksemplar muutub tehingute grupi isandaks.
Seega saavad lukustused olla rakendatud lihtsalt koordinaatori mÀlus olevate HashMap'ide kujul.
Koordinaatorite rikkeid
Kuna ĂŒks koordinaator teenindab eranditult tehingute gruppi, on ÀÀrmiselt oluline kiiresti tuvastada tema rike, et uue tehingu proovimine mahuks ajavahemikku. Selle kiire ja usaldusvÀÀrne tegemiseks rakendasime tĂ€ieliku linkimise kvora hearbeat protokolli:
Igas andme keskuses on vĂ€hemalt kaks koordinaatori sĂ”lme. Aeg-ajalt saadab iga koordinaator teistele koordinaatoritele sĂŒdame löögi sĂ”numi, teavitades neid oma toimimisest ning millistelt koordinaatoritelt on ta viimati sĂŒdame löögi sĂ”numeid saanud.

Saades sarnast teavet teistelt nende sĂŒdame löögi sĂ”numites, otsustab iga koordinaator, millised klastris olevad sĂ”lmed toimivad ja millised mitte, jĂ€rgides kvoorumi pĂ”himĂ”tet: kui sĂ”lm X on saanud enamiku sĂ”lmede poolt klastris teavet normaalsest sĂ”numite vastuvĂ”tmisest sĂ”lmelt Y, siis toimib Y. Vastupidi, niipea kui enamus teatab sĂ”lmelt Y sĂ”numite kadumisest, tĂ€hendab see, et Y on rikki lĂ€inud. Huvi pĂ€rast, kui kvoorum teatab sĂ”lmele X, et ta ei saa temalt enam sĂ”numeid, hakkab sĂ”lm X pidama end rikki lĂ€inuks.
Heartbeat-sĂ”numite edastamine toimub suure sagedusega, umbes 20 korda sekundis, 50 ms intervalliga. Java puhul on raske tagada rakenduse vastust 50 ms jooksul, kuna pauside kestus, mida pĂ”hjustab prĂŒgikoristaja, on sarnane. Oleme suutnud saavutada sellise vastuseaja, kasutades G1 prĂŒgikoristajat, mis vĂ”imaldab mÀÀrata GC pauside kestuse sihte. Siiski, mĂ”nikord, harva, ĂŒletavad prĂŒgikoristaja pausid 50 ms, mis vĂ”ib viia vale tĂ”rke avastamiseni. Selle vĂ€ltimiseks ei teata koordinaator kaug-noodi tĂ”rkest kohe, kui esimene heartbeat-sĂ”num temalt kaob, vaid ainult siis, kui mitu jĂ€rjestikkust kaduma lĂ€heb. Nii oleme suutnud saavutada koordinaatori nodi tĂ”rke avastamise 200 ms jooksul.
Aga pole piisav lihtsalt mÔista, milline nodi on lakanud töötamast. Midagi tuleb sellega ette vÔtta.
Varu
Klassikaline skeem eeldab meistri tĂ”rke korral uue valimist ĂŒhe kaudu algoritmid. Kuid sellistel algoritmidel on tuntud probleemid konvergentsi ja valimiste protsessi kestusega. Selliseid tĂ€iendavaid viivitusi oleme suutnud vĂ€ltida koordinaatorite asendamise skeemi abil tĂ€ielikult ĂŒhendatud vĂ”rgus:

Oletame, et soovime teostada tehingut grupis 50. Eeltingimusena mÀÀratleme asendamise skeemi, st millised sĂ”lmed teostavad grupi 50 tehingud, kui peamine koordinaator ebaĂ”nnestub. Meie eesmĂ€rk on sĂ€ilitada sĂŒsteemi töökindlus, kui andmekeskus ei tööta. MÀÀratleme, et esimene varu on sĂ”lm teisest andmekeskusest ja teine varu on sĂ”lm kolmandast. See skeem valitakse ĂŒks kord ja see ei muutu, kuni klasteri topoloogia muutub, st kuni sellesse ei lisandu uusi sĂ”lmi (mis juhtub vĂ€ga harva). Uue aktiivse meistri valimise jĂ€rjekord vanast ebaĂ”nnestumise korral on alati jĂ€rgmine: aktiivseks meistriks saab esimene varu, ja kui see enam ei tööta â siis teine varu.
Selline skeem on usaldusvÀÀrsem kui universaalne algoritm, kuna uue meistri aktiveerimiseks piisab vanast ebaÔnnestumise fakti kindlaksmÀÀrimisest.
Kuidas saavad kliendid aru, milline meister praegu töötab? 50 ms jooksul ei ole vÔimalik jagada teavet tuhandetele klientidele. VÔib juhtuda, et klient saadab pÀringu tehingu avamiseks, teadmata, et see meister ei tööta enam, ning pÀring jÀÀb ajutiseks. Selle vÀltimiseks saadavad kliendid spekulatiivselt pÀringu tehingu avamiseks kohe grupimeistrile ja mÔlemale tema varumeistrile, kuid vastab sellele pÀringule ainult see, kes on sel hetkel aktiivne meister. KÔik edasine suhtlemine tehingu raames toimub kliendi ja ainult aktiivse meistri vahel.
Varumeistrid, kes saavad pĂ€ringud mitte enda tehingute kohta, paigutavad need sĂŒndimata tehingute jĂ€rjekorda, kus need hoiavad mĂ”nda aega. Kui aktiivne meister sureb, töötleb uus meister jĂ€rjekorras olevaid tehingu avamise pĂ€ringuid ja vastab kliendile. Kui klient on juba jĂ”udnud avada tehingu vana meistri kaudu, siis teist vastust ignoreeritakse (ja ilmselgelt selline tehing ei lĂ”peta ning kordub kliendi poolt).
Kuidas tehing töötab
Oletame, et klient saatis koordinaatorile taotluse tehingu avamiseks sellise ĂŒksuse jaoks, millel on selline esmase vĂ”tme vÀÀrtus. Koordinaator blokeerib selle ĂŒksuse ja paigutab selle mĂ€lus blokeeringute tabelisse. Kui vajalik, loeb koordinaator selle ĂŒksuse salvestusest ja salvestab saadud andmed koordinaatori mĂ€lu tehingu olekusse.

Kui klient soovib tehingus andmeid muuta, saadab ta koordinaatorile taotluse ĂŒksuse muudatuste tegemiseks, ning koordinaator paigutab uued andmed tehingute oleku tabelisse mĂ€lus. Sellega on salvestamine lĂ”petatud â salvestust ei toimu.

Kui klient kĂŒsib aktiivse tehingu raames oma muudetud andmeid, toimib koordinaator jĂ€rgmiselt:
- kui ID on juba tehingus, siis andmed vÔetakse mÀlu;
- kui ID mĂ€lu ei ole, siis puuduvad andmed loetakse nodi salvestustest, ĂŒhendatakse olemasolevaga mĂ€lus ja tulemus antakse kliendile.
Seega vÔib klient lugeda oma muudatusi, kuid teised kliendid neid muudatusi ei nÀe, kuna need hoitakse ainult koordinaatori mÀlus; nodides Cassandra's neid veel ei ole.

Kliendi saadetud commit'i korral salvestab teenuse mĂ€llu jÀÀnud oleku koordinaator logged batch'ina, mis saadetakse juba logged batch'ina Cassandra ladudesse. Ladude ĂŒlesanne on tagada, et see pakett rakendataks atomaarsetena (tĂ€ielikult) ning naasta vastus koordinaatorile, kes vabastab lukud ja kinnitab tehingu edukust kliendile.

TagasitÔmbamiseks piisab koordinaatorist vaid mÀluruumi vabastamisest, mis on tehingu oleku jaoks reserveeritud.
Eelnimetatud tÀiustuste tulemusena oleme rakendanud ACID pÔhimÔtteid:
- Atomaarne. See tagab, et ĂŒkski tehing ei fikseerita sĂŒsteemis osaliselt: kas tehakse kĂ”ik alamoperatsioonid vĂ”i ei tehta ĂŒhtegi. Meie ettevĂ”ttes jĂ€rgime seda pĂ”himĂ”tet logged batch'i kaudu Cassandra's.
- Konsistentsus. Iga edukas tehing fikseerib mÀÀratletud tulemused. Kui tehingu avamise ja osade operatsioonide tÀitmise jÀrel selgub, et tulemus on ebaseaduslik, toimub tagasivÔtmine.
- Isolatsioon. Tehingu tÀitmisel ei tohi samal ajal toimuvad tehingud mÔjutada selle tulemusi. KonkurentsivÔimelised tehingud on koordinaatori pessimistic lock'dega isoleeritud. TehinguvÀlised lugemised jÀrgivad isoleerimise pÔhimÔtet Read Committed tasemel.
- Stabiilsus. ĂkskĂ”ik millised probleemid madalamatel tasemetel â sĂŒsteemi voolukatkestus, riistvara tĂ”rge â peaksid edukalt lĂ”petatud tehingute muudatused jÀÀma alles pĂ€rast sĂŒsteemi taastamist.
Lugemine indeksite kaudu
VÔtame lihtsa tabeli:
CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
âŠ)See sisaldab ID-d (peamine vĂ”ti), omaniku ja muutmise kuupĂ€eva. Peame tegema vĂ€ga lihtsa pĂ€ringu â valima andmed omaniku jĂ€rgi, kelle muudatused on tehtud «viimase 24 tunni» jooksul.
SELECT *
WHERE owner=?
AND modified>?Selle sarnase pĂ€ringu kiireks töötlemiseks tuleb klassikalises SQL andmebaasis luua indeks veergude (owner, modified) alusel. Sellise ĂŒlesande tĂ€itmine on nĂŒĂŒd lihtne, kuna meil on ACID garantiid!
Indeksid C*One
On algne tabel fotodega, mille kirje ID on peamine vÔti.

C*One loob uue tabeli indeksi jaoks, mis on algse koopia. VÔti vastab indeksile, samas sisaldab see ka algse tabeli peavÔtit:

NĂŒĂŒd saab pĂ€ringu «omaniku kohta viimase 24 tunni jooksul» ĂŒmber kirjutada kui select teise tabeli jaoks:
SELECT * FROM i1_test
WHERE owner=?
AND modified>?Algse tabeli photos ja indeksi i1 andmete kooskĂ”la sĂ€ilib automaatselt koordineerija kaudu. Ăheainsa andmeskeemi alusel, kui muudetakse, genereerib koordineerija muudatuse ja meeles peab mitte ainult pĂ”hitĂ€hted, vaid ka koopiate muudatused. TĂ€iendavaid toiminguid indeksi tabeliga ei tehta, logisid ei loeta ega lukustusi ei kasutata. Seega indekseerimise lisamine tarbib peaaegu mitte mingit ressurssi ja ei mĂ”juta modifikatsioonide rakendamise kiirus.
ACID tehnoloogia abil suutsime luua indekseid, nagu SQL-is. Need on jÀrjepidevad, skaleeritavad, töötavad kiiresti, vÔivad olla komposiitindeksid ning on integreeritud CQL-i pÀringukeelde. Indeksite toetamiseks ei ole vaja rakenduskoodi muuta. KÔik on lihtne nagu SQL-is. Ja mis kÔige tÀhtsam, indeksid ei mÔjuta tehinguliste algsetabelite muudatuste tÀitmise kiirus.
Mis vÀlja tuli
Arendasime C*One kolm aastat tagasi ja kÀivitasime selle tööstuslikuks kasutamiseks.
Kuidas oli meie tulemus? Vaadake nĂ€iteks fotode töötlemise ja salvestamise alamsĂŒsteemi, mis on ĂŒks sotsiaalvĂ”rgustike kĂ”ige olulisemaid andmeliike. RÀÀgime mitte fotode fĂŒĂŒsilisest sisust, vaid kĂ”ikidest vĂ”imalikest metaandmetest. Praegu on âĐĐŽĐœĐŸĐșлаŃŃĐœĐžĐșĐ°Ń â umbes 20 miljardit sellist kirjet, sĂŒsteem kĂ€itleb 80 000 lugemisepĂ€ringut sekundis, kuni 8 000 ACID-tehingut sekundis, mis on seotud andmete muutmisega.
Kui kasutasime SQL-i, mille replikatsiooni faktor oli 1 (aga RAID 10), siis salvestati piltide metaandmed 32 masina kĂ”rge kĂ€ttesaadavuse klastrisse Microsoft SQL Serveriga (pluss 11 varukohta). Varukoopiate hoidmiseks eraldati 10 serverit. Kokku 50 kulukat masinat. Samal ajal töötas sĂŒsteem nominatiivsel koormusel, ilma tĂ€iendava ressurssideta.
PĂ€rast uut sĂŒsteemi migratsiooni saime replikatsiooni faktoriks 3 â iga andmekeskuse kohta ĂŒks koopia. SĂŒsteem sisaldab 63 Cassandra salvestusnodu ja 6 koordinaatorit, kokku 69 serverit. Kuid need masinad on oluliselt odavamad, nende koguhind on umbes 30% SQL sĂŒsteemi maksumusest. Koormus pĂŒsib 30% tasemel.
C*One rakendamisega vĂ€henesid ka viivitused: SQL-is vĂ”ttis kirjutamine aega umbes 4,5 ms. C*One-is on see umbes 1,6 ms. Tehingu kestus on keskmiselt alla 40 ms, kinnitamine toimub 2 ms jooksul, lugemise ja kirjutamise kestus â keskmiselt 2 ms. 99. protsentil on see vaid 3-3,1 ms, ajaĂŒlekande juhtumeid on vĂ€henenud 100 korda â kĂ”ik tĂ€nu laiale spekulatsioonide rakendusele.
Praeguseks on suurem osa SQL Serveri node'dest vĂ€lja lĂŒlitatud, uusi tooteid arendatakse ainult C*One kasutades. Oleme C*One'i kohandanud tööks meie pilves. , mis on vĂ”imaldanud kiirendada uute klastrite seadistamist, lihtsustada konfiguratsiooni ja automatiseerida haldamist. Ilma lĂ€htekoodita oleks see olnud mĂ€rgatavalt keerulisem ja vaevalisem.
Praegu töötame teiste meie hoidlate pilve viimise kallal â aga see on juba hoopis teine lugu.
Allikas: habr.com
