
Kuni hiljuti hoiti Odnoklassnikovis umbes 50 TB reaalajas töödeldud andmeid SQL Serveris. Sellise mahuga kiire ja usaldusvÀÀrse, veelgi enam, tĂ”rgetekindla andmekeskuse juurdepÀÀsu tagamine, kasutades SQL andmebaasi, on peaaegu vĂ”imatu. Tavaliselt kasutatakse sellistes olukordades ĂŒhte NoSQL-andmehoidlatest, kuid mitte kĂ”ike ei saa ĂŒle viia NoSQL-i: mĂ”ned ĂŒksused nĂ”uavad ACID-tehingute garantiisi.
See viis meid NewSQL-andmehoidla kasutamiseni, st andmebaasi, mis pakub tĂ”rketaluvust, skaleeritavust ja NoSQL-sĂŒsteemide kiirus, kuid sĂ€ilitab samas klassikaliste sĂŒsteemide ACID-garantii. Tööstuslikke sĂŒsteeme selle uue klassi jaoks on vĂ€he, seega rakendasime sellise sĂŒsteemi ise ja kĂ€ivitasime selle tööstuslikuks kasutamiseks.
Kuidas see toimib ja mis vĂ€lja tuli â loe edasi.
TĂ€na on âOdnoklassnikoviteâ kuine publik ĂŒle 70 miljoni unikaalse kĂŒlastaja. Me suurima sotsiaalmeedia platvormi seas maailmas ja kahekĂŒmne hulgas veebisaitide seas, kus kasutajad veedavad kĂ”ige rohkem aega. âOKâ infrastruktuur töötleb vĂ€ga suuri koormusi: ĂŒle miljjoni HTTP-pĂ€ringu sekundis frontides. Ăle 8000 serveri moodustavad serveripargi, mis asuvad ĂŒksteise lĂ€hedal â neljas Moskva andmekeskuses, mis vĂ”imaldab tagada vĂ”rgu latentsuse alla 1 ms nende vahel.
Oleme Cassandra't kasutanud alates 2010. aastast, alustades versioonist 0.6. TĂ€na on kasutuses mitukĂŒmmend klastrit. Kiireim klaster töötleb ĂŒle 4 miljoni operatsiooni sekundis, samas kui suurim salvestab 260 TB.
Kuid kĂ”ik need on tavalised NoSQL-klastrid, mida kasutatakse andmete sĂ€ilitamiseks. Soovisime aga asendada pĂ”hikooskĂ”lastatud andmehoidla, Microsoft SQL Serveri, mida on kasutatud âOdnoklassnikoviteâ loomise hetkest. Andmehoidla koosnes rohkem kui 300 SQL Server Standard Edition masinast, millel oli 50 TB andmeid â Ă€rilisi entiteete. Need andmed muudetakse ACID-tehingute kĂ€igus ja nĂ”uavad .
SQL Serveri andmete jaotamiseks sĂ”lmedesse kasutasime nii vertikaalset kui ka horisontaalset (sharding). Ajalooliselt oleme kasutanud lihtsat andmete ĆĄardimise skeemi: igale ĂŒksusele mÀÀrati token - funktsioon ĂŒksuse ID-st. Ăksused, millel on sama token, pandi ĂŒhele SQL-serverile. Master-detail tĂŒĂŒpi suhe rakendati nii, et pĂ”hikirje ja selle aluskirje tokenid olid alati samad ja paiknesid samal serveril. SotsiaalvĂ”rgustikus genereeritakse peaaegu kĂ”ik kirjed kasutaja nime alt - see tĂ€hendab, et kĂ”iki kasutaja andmeid hoitakse ĂŒhe funktsionaalsete sĂŒsteemide raames ĂŒhel serveril. Seega osalesid Ă€ritehingutes peaaegu alati sama SQL-serveri tabelid, mis vĂ”imaldas andmete jĂ€rjepidevust tagada kohalike ACID-tehingute kaudu, ilma vajaduseta kasutada jaotatud ACID-tehinguid.
Ć ardingu ja SQL-i töö kiirendamiseks:
- Ei kasuta vĂ€lismaiseid vĂ”tme piiranguid, kuna ĆĄardimise puhul vĂ”ib ĂŒksuse ID olla teisel serveril.
- Ei kasuta salvestatud protseduure ega trikke, kuna need koormavad andmebaasi CPU-d.
- Ei kasuta JOIN-e eelnevatel pÔhjustel ja paljusid juhuslikke lugemisi ketast.
- VÀlise tehingu puhul vÀhendame ummikute riski, kasutades Read Uncommitted isolatsiooni taset.
- Teostame ainult lĂŒhikesi tehinguid (keskmiselt alla 100 ms).
- Ei kasuta mitmerealisi UPDATE ja DELETE, kuna need pĂ”hjustavad palju ummikuid â uuendame ainult ĂŒhte kirjet.
- KĂŒsimused teostame alati ainult indeksite kaudu - kĂŒsimus, mille plaan nĂ€eb ette tĂ€ieliku tabeli vaatamist, tĂ€hendab meie jaoks andmebaasi ĂŒlekoormust ja selle riket.
Need sammud on vĂ”imaldanud SQL-serveritest peaaegu maksimumvĂ”imsust vĂ€lja pigistada. Kuid probleeme tuli ĂŒha rohkem ja rohkem. Vaatame neid lĂ€hemalt.
SQL-i probleemid
- Kuna kasutasime isekirjutatud ƥardimist, viidi uute ƥardide lisamine manuaalselt lÀbi administraatorite poolt. Kogu selle aja vÀltel ei teeninud skaleeritavad andmete koopiad pÀringuid.
- Kuna andmete arv tabelis suureneb, vÀheneb lisamise ja muutmise kiirus, olemasoleva tabeli indeksite lisamisel kiirus langeb kordades, indeksite loomine ja uuesti loomine toimub seiskumisega.
- Toodangu vÀikese arvu Windowsi SQL Serverite olemasolu raskendab infrastruktuuri haldamist
Kuid kĂ”ige suurem probleem on â
Talitluskatkestustunne
Klassikalise SQL-serveri talitlushĂ€ired on halvad. Oletame, et teil on ainult ĂŒks andmebaasi server ja see ebaĂ”nnestub ĂŒks kord iga kolme aasta jĂ€rel. Sel ajal ei tööta veebisait 20 minutit, mis on aktsepteeritav. Kui teil on 64 serverit, ei tööta veebisait juba kord iga kolme nĂ€dala jĂ€rel. Ja kui teil on 200 serverit, ei tööta veebisait iga nĂ€dal. See on probleem.
Mida saab teha SQL-serveri talitlushÀirete tÔstatamiseks? Wikipedia soovitab meil luua : kus igasuguse komponendi tÔrke korral on olemas duplikaat.
See nĂ”uab kallite seadmete parki: ulatuslikud duplikaadid, kiudoptiline kaabeldus, jagatud salvestus ja ka varu sisselĂŒlitamine ei toimi usaldusvÀÀrselt: umbes 10% sisselĂŒlitamistest lĂ”ppeb varu sĂ”lme rikke tĂ”ttu, mis jĂ€rgneb pĂ”hikliendile.
Kuid sellise kĂ”rge kĂ€ttesaadavusega klastrite peamine puudus on nullkĂ€ttesaadavus andmekeskuse tĂ”rke korral, kus see asub. "Odnoklassniki" omab nelja andmekeskust ning me peame tagama, et see töötab tĂ€ieliku rikke korral ĂŒhes neist.
Selle probleemi lahendamiseks vĂ”iksime kasutada replikatsiooni, mis on integreeritud SQL Serverisse. See lahendus on mĂ€rkimisvÀÀrselt kallim tarkvara maksumuse tĂ”ttu ja kannatab hĂ€sti tuntud replikatsiooniga seotud probleemide all â ettearvamatud tehingu viivitused sĂŒnkroonses replikatsioonis ning viivitused replikatsioonide rakendamisel (ja seega ka kadunud muudatused) asĂŒnkroonse puhul. Eeldatav teeb selle valiku meie jaoks tĂ€ielikult kasutamatuks.
KĂ”ik need probleemid nĂ”udsid radikaalset lahendust ja me alustasime nende ĂŒksikasjalikku analĂŒĂŒsi. Siin peame tutvuma sellega, mida SQL Server pĂ”himĂ”tteliselt teeb â tehingud.
Lihtne tehing
Vaatame kÔige lihtsamat tehingut, vaatenurgast rakenduslikku SQL-programmeerijat: foto lisamine albumisse. Albumid ja fotod on salvestatud erinevatesse tabelitesse. Albumil on avalike fotode loend. Siis jaguneb selline tehing jÀrgnevateks sammudeks:
- Lukustame albumi selle vÔtme jÀrgi.
- Loome kirje fotode tabelis.
- Kui fotol on avalik staatuse, siis suurendame albumis avalike fotode loendit, uuendame kirjet ja kinnitame tehingu.
VÔi pseudokoodina:
TX.start("Albums", 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 Ă€ritehingu stsenaarium on andmete lugemine andmebaasist rakendusserveri mĂ€llu, millegi muutmine ja uute vÀÀrtuste salvestamine tagasi andmebaasi. Tavaliselt vĂ€rskendame sellises tehingus mitu ĂŒksust, mitu tabelit.
Tehingu kĂ€igus vĂ”ib tekkida konkurentsiaalne muutmine sama andmebaasi andmete osas teises sĂŒsteemis. NĂ€iteks vĂ”ib antispam otsustada, et kasutaja on kahtlane ja seetĂ”ttu ei tohi kĂ”ik kasutaja fotod enam avalikud olla, need tuleb saata modereerimisele, mis tĂ€hendab, et photo.status tuleb muuta mĂ”neks muuks vÀÀrtuseks ja vastavad loendurid tuleb tagasi keerata. Ilmselgelt, kui see operatsioon toimub ilma atomaarse rakendamise ja konkurentide muudatuste isoleerimise garantiideta, nagu , ei ole tulemus 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 Àrielementidega sama tehingu raames, on kogu Odnoklassniki eksisteerimise ajal kirjutatud vÀga palju. Kogemuse pÔhjal NoSQL-i migreerimisel teame, et suurimad raskused (ja ajakulu) tekivad vajadusest arendada koodi, mis tagab andmete jÀrjepidevuse. SeetÔttu pidasime uue andmebaasi peamiseks nÔudeks ACID-tehingute reaalset tagamist rakendusloogika jaoks.
Muud, mitte vÀhem tÀhtsad nÔuded olid:
- Andmekeskuse tÔrke korral peavad nii lugemine kui kirjutamine uude andmebaasi olema vÔimalikud.
- Praeguse arenduskiirus jÀÀtmine. See tÀhendab, et uue andmebaasiga töötades peaks koodihulk olema ligikaudu sama, ei tohi tekkida vajadust koguda andmebaasi, arendada konfliktide lahendamise algoritme, sÀilitada teise astme indekseid jne.
- Uue andmebaasi töökiirus peab olema piisavalt kÔrge nii andmete lugemisel kui tehingute töötlemisel, mis tÔhusalt tÀhendab, et akadeemiliselt rangeid, universaalseid, kuid aeglaseid lahendusi, nagu nÀiteks .
- Automaatne skaleerimine reaalajas.
- TavapÀraste odavate serverite kasutamine ilma eksootiliste seadmete ostmise vajaduseta.
- Andmehoidla arendamise vÔimalus ettevÔtte arendajate poolt. TeisisÔnu, eelistasime oma vÔi avatud lÀhtekoodiga lahendusi, eelistatult Java platvormil.
Lahendused, lahendused
AnalĂŒĂŒsides vĂ”imalikke lahendusi, jĂ”udsime kahe arhitektuuri valiku juurde:
Esimene â vĂ”tta mistahes SQL-server ja rakendada vajalikud vigadetaluvus, skaleerimise mehhanism, vigadetaluv klaster, konfliktide lahendamine ning jaotatud, usaldusvÀÀrsed ja kiired ACID-tehingud. Hinnasime seda valikut kui pigem keerulist ja aeganĂ”udvat.
Teine variant â kasutada valmis NoSQL-andehoidlat, milles on rakendatud skaleerimine, vigadetaluv klaster ja konfliktide lahendamine ja rakendada tehingud ning SQL ise. Esmapilgul tundub isegi SQL-i rakendamine, rÀÀkimata ACID-tehingutest, aastaid kestev ĂŒlesanne. Kuid hiljem mĂ”istsime, et nende SQL-i vĂ”imaluste kogum, mida me praktikas kasutame, on kaugel ANSI SQL-ist nii kaugel kui on ANSI SQL-ist. LĂ€hemalt uurides CQL-i, jĂ”udsime jĂ€reldusele, et see on piisavalt lĂ€hedal sellele, mida me vajame.
Cassandra ja CQL
Nii et, mis on Cassandra huvitav, millised vÔimalused tal on?
Esiteks saab siin luua tabeleid, mis toetavad erinevaid andmetĂŒĂŒpe, vĂ”ib teha SELECT vĂ”i UPDATE pĂ€ringuid primaarvĂ”tme jĂ€rgi.
CREATE TABLE photos (id bigint KEY, owner bigint,âŠ);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET ⊠WHERE id=?;Replikate andmete jĂ€rjepidevuse tagamiseks kasutab Cassandra KĂ”ige lihtsamas juhus tĂ€hendab see, et kolme ĂŒhe ja sama rea koopiat, mis asuvad klastris erinevates noodes, peetakse salvestamise operatsiooni edukaks, kui enamus nodes (st kaks kolmest) on kinnitanud, et see operatsioon Ă”nnestus. Rida andmeid loetakse kooskĂ”lastatuks, kui lugemise ajal on suur enamus noode kĂŒsitud ja need on oma kinnitused andnud. Nii tagatakse kolme koopia olemasolul andmete tĂ€ielik ja kohene kooskĂ”lastamine ĂŒhe node'i rikke korral. See lĂ€henemine lubas meil rakendada veelgi usaldusvÀÀrsemat skeemi: alati saata pĂ€ringud kĂ”ikidele kolmele koopiale, oodates vastust kahest kiireimast. HĂ€iritud kolmanda koopia vastus jĂ€etakse sellisel juhul tĂ€helepanuta. Probleeme vĂ”ib tekkida aeglaselt vastavaks muutuvast node'ist - nĂ€iteks viivitustest, JVM-i prĂŒgikoristusest, Linuxi kerneli otsesest mĂ€lukoristusest, riistvara riketest vĂ”i vĂ”rgu katkemisest. Kuid see ei mĂ”juta kliendi operatsioone ega andmeid.
LĂ€henemist, kus pöördume kolme node'i poole ja saame vastuse kahest, nimetatakse : pĂ€ring ĂŒlearustele koopiatele saadetakse enne, kui need "maha kukuvad".
Cassandra ĂŒheks teiste eelisteks on Batchlog - mehhanism, mis garanteerib kas paketi tĂ€ieliku rakendamise vĂ”i tĂ€ieliku rakendamata jĂ€tmise. See vĂ”imaldab meil lahendada A ACID-is - atomuaarsuse pakend.
Cassandra kĂ”ige lĂ€hemal asuvate tehingute seas on nn "". Kuid nad on kaugel "pĂ€ris" ACID-tehingutest: tegelikult on see vĂ”imalus teha ainult ĂŒhe kirje andmetega, kasutades raskealuslike Paxose protokolli konsensust. SeetĂ”ttu ei ole nende tehingute kiirus suur.
Mida me Cassandra'st puudu tundsime
Nii olid meil plaanis rakendada Cassandra's tĂ”elisi ACID-tehinguid. Mille abil vĂ”iksime hĂ”lpsasti saavutada kaks muud mugavat omadust traditsioonilistes andmebaasihaldussĂŒsteemides: jĂ€rjepidevad kiired indeksid, mis vĂ”imaldaksid meil teha andmevalimisi mitte ainult esmase vĂ”tme ja tavalise monotone autonoomse ID generaatori pĂ”hjal.
C*One
Nii sĂŒndis uus andmebaasisĂŒsteem C*One, mis koosneb kolmest tĂŒĂŒpi serverinode'ist:
- Salvestused - (peaaegu) standardsed Cassandra serverid, mis vastutavad andmete sĂ€ilitamise eest kohalikest kĂ”vaketastest. Koormuse ja andmemahtu suurenedes on nende arvu lihtne suurendada kĂŒmnetest ja sadadest.
- Tehingute koordineerimine â tagab tehingute tĂ€itmise.
- Kliendid â rakenduste serverid, mis viivad ellu Ă€riprotsesse ja kĂ€ivitavad tehingud. Selliseid kliente vĂ”ib olla tuhandeid.

KĂ”ik serverid, olenemata tĂŒĂŒbist, kuuluvad ĂŒhisesse klastrisse, kasutavad omavaheliseks suhtlemiseks sisemist sĂ”numite protokolli Cassandra ja klastri teabe vahetamiseks. Heartbeat'i abil saavad serverid teineteise rikkeid teada, sĂ€ilitavad ĂŒhtse andmeskeemi â tabelid, nende struktuur ja replikatsioon; partitsioneerimise skeem, klastrite topoloogia jne.
Kliendid

Standardsete draiverite asemel kasutatakse Fat Client reĆŸiimi. Selline sĂ”lm ei salvesta andmeid, kuid vĂ”ib toimida pĂ€ringute tĂ€itmise koordinaatorina. See tĂ€hendab, et klient tĂ€idab ise oma pĂ€ringute koordineerimise funktsiooni: kĂŒsib salvestuste koopiaid ja lahendab konflikte. See ei ole mitte ainult usaldusvÀÀrsem ja kiirem kui standardne draiver, mis nĂ”uab suhtlemist kaugkoordinatsiooniga, vaid vĂ”imaldab ka pĂ€ringute edastamise haldamist. Avatud tehingu korral suunatakse pĂ€ringud salvestusse. Kui klient on tehingu avanud, suunatakse kĂ”ik tehingu raames tehtud pĂ€ringud tehingute koordinaatorisse.

Tehingute koordinaator C*One
Koordinaator â see, mille me C*One jaoks nullist vĂ€lja töötasime. Selle ĂŒlesanne on tehingute, lukustuste ja tehingute rakendamise jĂ€rjekorra haldamine.
Iga teenindatava tehingu jaoks genereerib koordinaator ajatempli: iga jĂ€rgneva aeg on suurem kui eelmise tehingu oma. Kuna Cassandras pĂ”hineb konfliktide lahendamise sĂŒsteem ajatemplitel (kahest konflikti allikast loetakse kehtivamaks see, millel on hilisem ajatempli vÀÀrtus), lahendatakse konflikt alati jĂ€rgneva tehingu kasuks. Nii oleme me realiseerinud â odav viis konfliktide lahendamiseks jaotatud sĂŒsteemis.
Lukustused
Isolatsiooni tagamiseks otsustasime kasutada kĂ”ige lihtsamat meetodit â pessimistlikke lukustusi kirje primaarvĂ”tme jĂ€rgi. TeisisĂ”nu, tehingu raames tuleb kirje esmalt lukustada, seejĂ€rel lugeda, muuta ja salvestada. Ainult pĂ€rast edukat kinnitamist vĂ”ib kirje lukust vabastada, et konkurentsivĂ”imelised tehingud saaksid seda kasutada.
Sellise lukustuse rakendamine on lihtne mittejaotatud keskkonnas. Jaotatud sĂŒsteemis on kaks peamist teed: kas rakendada jaotatud lukustust klastris vĂ”i jaotada tehingud nii, et tehingud, mis hĂ”lmavad ĂŒhte kirjet, teenindab alati sama koordinaator.
Kuna meie juhul on andmed juba jaotatud kohalike tehingute gruppides SQL-is, otsustati siduda iga kohaliku tehingu grupiga koordinaatorid: ĂŒks koordinaator teostab kĂ”ik tehingud, mille token on 0-9, teine - 10-19, ja nii edasi. Tulemuseks on, et iga koordinaatori eksemplar muutub tehingute grupi valitsejaks.
Siis saavad lukustused olla rakendatud nagu tavaline HashMap koordinaatori mÀlus.
Koordinaatorite rikke
Kuna ĂŒks koordinaator teenindab eriliselt tehingute gruppi, on vĂ€ga oluline kiiresti kindlaks teha tema rike, et tehingu uuesti tĂ€itmine mahtuks ajavahemikku. Selleks, et see oleks kiire ja usaldusvÀÀrne, rakendasime tĂ€ielikult ĂŒhendatud kvoorumi heartbeat protokolli:
Iga andmekeskuse kohta paikneb vÀhemalt kaks koordinaatori sÔlme. Aeg-ajalt saadab iga koordinaator teistele koordinaatoritele heartbeat-sÔnumi ja teavitab neid oma toimimisest, samuti sellest, milliseid heartbeat-sÔnumeid ta viimati teistelt koordinaatoritelt klastris sai.

Saades sarnast teavet teistelt oma heartbeat-sÔnumites, otsustab iga koordinaator, millised klastri sÔlmed töötavad ja millised mitte, jÀrgides kvoorumi pÔhimÔtet: kui sÔlm X sai enamiku klastri sÔlmedelt teavet, et sÔlm Y on sÔnumid normaalselt saanud, siis Y töötab. Ja vastupidi, niipea, kui enamus teatab sÔnumite kadumisest sÔlmelt Y, siis Y on rikutud. Huvitav on see, et kui kvoorum teatab sÔlmele X, et ta ei saa temalt enam sÔnumeid, arvab see iseend, et on rikutud.
Heartbeat-Ă”nnesĂ”numid saadetakse suure sagedusega, umbes 20 korda sekundis, 50 ms intervalliga. Java-s on raske tagada rakenduse vastust 50 ms jooksul, kuna prĂŒgikorjaja tekitab vĂ”rdse pikkusega pause. Ănnestus saavutada selline vastus G1 prĂŒgikorjajaga, mis vĂ”imaldab mÀÀrata GC peatuste kestuse eesmĂ€rgi. Siiski, harva, vĂ”ivad prĂŒgikorjaja pausid ĂŒletada 50 ms, mis vĂ”ib viia vale riketeavitamiseni. Selle vĂ€ltimiseks ei teata koordinaator koheselt kaugnoodi tĂ”rke kohta, kui esimene heartbeat-sĂ”num lĂ€heb kaduma, vaid ainult siis, kui mitu jĂ€rjestikust on kadunud. N nii Ă”nnestus saavutada koordinaatori noodi rikete avastamine 200 ms jooksul.
Kuid vÀhe on lihtsalt aru saada, milline nool on lakanud toimimast. Peame midagi ette vÔtma.
Varustamine
Klassikaline skeem eeldab, et juhendi rikke korral kĂ€ivitame uue valimise ĂŒhega algoritmidest. Sellistel algoritmidel on aga hĂ€sti teada probleemid konvergentsiga ajas ja valimiste protsessi kestuse osas. Kuigi nende lisaviivitustega oleme suutnud vĂ€ltida, kasutades koordinaatorite asendamise skeemi tĂ€ielikus ĂŒhenduses olevas vĂ”rgus:

Oletame, et soovime teostada tehingut rĂŒhmas 50. MÀÀrame eelnevalt asendamise skeemi, st millised noodid viivad rĂŒhmas 50 tehingud ellu, juhul kui peamine koordinaator peaks ebaĂ”nnestuma. Meie eesmĂ€rk on sĂ€ilitada sĂŒsteemi töökindlus andmekeskuse tĂ”rke korral. MÀÀrame, et esmakordne varu on nool teisest andmekeskusest, ja teiseks varuks â nool kolmandast. See skeem valitakse ĂŒks kord ja ei muutu, kuni klastrite topoloogia ei muutu, st kuni ei liitu uusi noode (mis juhtub vĂ€ga harva). Uue aktiivse juhendi valimise jĂ€rjestus vanade tĂ”rke korral on alati jĂ€rgmine: aktiivseks juhiks saab esimene varu ning kui ka see enam ei toimi â siis teine varu.
See skeem on usaldusvÀÀrsem kui universaalne algoritm, kuna uue juhendi aktiveerimiseks piisab vana tÔrke tuvastamisest.
Kuid kuidas saavad kliendid aru, kes meistritest hetkel töötab? 50 ms jooksul ei ole vĂ”imalik teavet saata tuhandetele klientidele. VĂ”ib juhtuda, et klient saadab pĂ€ringu tehingu avamiseks, teadmata, et see meister ei tööta enam, ja pĂ€ring lĂŒkatakse ajakavale. Selle vĂ€ltimiseks saadavad kliendid spekulatiivselt pĂ€ringu tehingu avamiseks kohe grupi meistrile ja tema kahe reservmeistrile, kuid vastab sellele pĂ€ringule ainult see, kes on hetkel aktiivne meister. Kogu hilisem suhtlus tehingu raames toimub ainult aktiivse meistriga.
Reservmeistrid, kes saavad pĂ€ringud mitte enda tehingute kohta, paigutavad need sĂŒndimata tehingute jĂ€rjekorda, kus nad hoiustatakse mĂ”nda aega. Kui aktiivne meister sureb, siis uus meister töötleb pĂ€ringud tehingute avamiseks oma jĂ€rjekorrast ja vastab kliendile. Kui klient on juba suutnud avada tehingu vana meistriga, siis teine vastus jĂ€etakse tĂ€helepanuta (ja ilmset ei saa selline tehing lĂ”pule viidud ning klient peab seda kordama).
Kuidas tehing töötab
Oletame, et klient saatis koordinaatorile pÀringu tehingu avamiseks sellise entiteedi jaoks, millel on selline pÔhivÔti. Koordinaator blokeerib selle entiteedi ja paigutab selle mÀlus blokeerimislauda. Vajadusel loeb koordinaator selle entiteedi salvestusest ja salvestab saadud andmed tehingu olekusse koordinaatori mÀllu.

Kui klient soovib tehingus andmeid muuta, saadab ta koordinaatorile pĂ€ringu entiteedi muutmiseks, mille puhul koordinaator paigutab uued andmed tehingute olekute tabelisse mĂ€llu. Sellega on kirjutamine lĂ”petatud â salvestusse kirjutamine ei toimu.

Kui klient kĂŒsib aktiivse tehingu raames enda muudetud andmeid, kĂ€itub koordinaator jĂ€rgmiselt:
- kui ID on tehingus juba olemas, siis andmed vÔetakse mÀlust;
- kui ID mĂ€lus puudub, siis loetakse puuduvad andmed sĂ”lme salvestustest, ĂŒhendatakse need juba olemasolevate andmetega mĂ€lus ning tulemus antakse kliendile.
Nii saab klient lugeda enda muudatusi, kuid teised kliendid neid muudatusi ei nĂ€e, sest need on talletatud ainult koordinaatori mĂ€lus, sĂ”lmedes Cassandraâs neid veel ei ole.

Kui klient saadab commit'i, salvestab koordinaator teenuse mÀlus olnud oleku logged batch'i, ja see juba logged batch'ina saadetakse Cassandra ladustamisse. Ladustamine teeb kÔik vajaliku, et see pakett oleks aatomaarne (tÀielikult) rakendatud, ja tagastab vastuse koordinaatorile, kes vabastab lukud ja kinnitab tehingu edukuse kliendile.

Ja juhul, kui tuleb tagasivÔtt, piisab koordinaatorist, et lihtsalt vabastada mÀlu, mis sisaldab tehingu olekut.
Ălaltoodud tĂ€iendustega oleme rakendanud ACID pĂ”himĂ”tteid:
- Aatomaarusus. See tagab, et ĂŒkski tehing ei salvestata sĂŒsteemi osaliselt, kas kĂ”ik selle alamoperatsioonid tĂ€idetakse vĂ”i ei tĂ€ideta ĂŒhtegi. Meie puhul sĂ€ilitatakse see pĂ”himĂ”te logged batch'i kaudu Casandsas.
- JÀrjepidevus. Iga edukas tehing fikseerib mÀÀratletud tulemused. Kui pÀrast tehingu avamist ja osa operatsioonide tÀitmist leitakse, et tulemus on mittesobiv, tehakse tagasivÔtt.
- Isolatsioon. Tehingu tÀitmise ajal ei tohiks parallel-tehingud mÔjutada selle tulemust. KonkurentsivÔimelised tehingud on isoleeritud koordinaatori pessimistlike lukustustega. VÀlistehingute lugemise korral jÀrgime isoleerituse pÔhimÔtet Read Committed tasandil.
- PĂŒsivus. ĂkskĂ”ik millised probleemid alumistel tasanditel â sĂŒsteemi voolukatkestus, seadmete tĂ”rge â, edukalt lĂ”petatud tehingu muudatused peavad jÀÀma alles pĂ€rast sĂŒsteemi taasfunktsioneerimist.
Lugemine indeksite kaudu
VÔtame lihtsa tabeli:
CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
âŠ)Sellest tabelist on ID (esmane vĂ”ti), omanik ja muutmise kuupĂ€ev. Peame tegema vĂ€ga lihtsa pĂ€ringu â valima andmed omaniku jĂ€rgi, kelle muudatuse kuupĂ€ev on "viimase 24 tunni" jooksul.
SELECT *
WHERE owner=?
AND modified>?Selle taolise pĂ€ringu kiireks töötlemiseks peab klassikalises SQL andmebaasis ehitama indeksid veergudele (owner, modified). Me saame seda teha piisavalt lihtsalt, kuna nĂŒĂŒd on meil ACID garantii!
Indeksid C*One
Olemas on fotosid sisaldav algne tabel, mille kande ID on esmane vÔti.

Indeksi jaoks loob C*One uue tabeli, mis on algse koopia. VÔti on sama, mis indeksile vastav vÀljend, samal ajal sisaldab see ka algse tabeli esmast vÔtit:

NĂŒĂŒd saab pĂ€ringu âomanik viimase 24 tunni jooksulâ ĂŒmber kirjutada valiku kaudu teiselt tabelilt:
SELECT * FROM i1_test
WHERE owner=?
AND modified>?Algse tabeli fotosid ja indeksit i1 kooskĂ”lastatakse automaatselt koordinaatori poolt. AinuĂŒksi andmeskeemi alusel genereerib ja salvestab koordinaator muudatuse mitte ainult pĂ”hiteabesse, vaid ka koopiate muudatused. TĂ€iendavaid toiminguid indeksitabeliga ei tehta, logisid ei loeta, lukustusi ei kasutata. See tĂ€hendab, et indeksite lisamine tarbib peaaegu mitte mingeid ressursse ja ei mĂ”juta oluliselt muudatuste rakendamise kiirus.
ACID-i abil oleme suutnud rakendada indekseid ânagu SQL-isâ. Need on kooskĂ”lastatud, skaleeritavad, töötavad kiiresti, vĂ”ivad olla koostatud ja sisseehitatud CQL-pĂ€ringu keelde. Indeksite toetamiseks ei ole vaja rakenduskoodi muuta. KĂ”ik on lihtne, nagu SQL-is. Ja mis kĂ”ige tĂ€htsam, indeksid ei mĂ”juta algse tehingute tabeli muudatuste tĂ€itmise kiirus.
Mis vÀlja tuli
Me arendasime C*One vÀlja kolm aastat tagasi ja kÀivitasime selle tööstuslikuks kasutuseks.
Mida me lĂ”puks saime? Hinnake seda meie fotode töötlemise ja salvestamise alamsĂŒsteemi nĂ€itel, mis on sotsiaalvĂ”rgustikus ĂŒks olulisemaid andmete tĂŒĂŒpe. RÀÀgime mitte ainult fotode tegelikest kehade, vaid ka erinevatest metaandmetest. Praegu on âOdnoklassnikitesâ umbes 20 miljardit sellist salvestust, sĂŒsteem töötleb 80 tuhat lugemisepĂ€ringut sekundis ja kuni 8 tuhat ACID-tehingut sekundis, mis on seotud andmete muutmisega.
Kui kasutasime SQL-i replikatsiooni teguriga = 1 (aga RAID 10. puhul), hoiti fotode metaandmed kĂ”rge kĂ€ttesaadavusega klastris, mis koosneb 32 masinast Microsoft SQL Serveriga (pluss 11 varukoopiat). Samuti oli eraldatud 10 serverit varukoopiate hoidmiseks. Kokku 50 kulukat masinat. Sel ajal töötas sĂŒsteem nominaalsel koormusel, ilma varu.
PĂ€rast ĂŒleminekut uuele sĂŒsteemile saime replikatsiooni teguri = 3 â iga andmekeskuse kohta ĂŒks koopia. SĂŒsteem koosneb 63 Cassandra salvestusnode'ist ja 6 masinast koordinaatoreid, kokku 69 serverit. Kuid need masinad on oluliselt odavamad, nende koguhind on umbes 30% SQL-i sĂŒsteemi hinnast. Samal ajal jÀÀb koormus 30% tasemele.
C*One rakendamisega vĂ€henesid ka viivitused: SQL-i kirjutamise operatsioon kestis umbes 4,5 ms. C*One-s â umbes 1,6 ms. Tehingu kestus on keskmiselt alla 40 ms, kinnitamine toimub 2 ms jooksul, lugemise ja kirjutamise kestus â keskmiselt 2 ms. 99. percentiili jaoks â vaid 3â3,1 ms, ajakulu vĂ€henes 100 korda â kĂ”ik tĂ€nu spekulatsioonide laialdasele kasutamisele.
KÀesolevaks ajaks on suurem osa SQL Serveri sÔlmedest vÀlja vÔetud, uusi tooteid arendatakse ainult C*One kasutades. Oleme kohandanud C*One meie pilve tööks. , mis vÔimaldas kiirendada uute klastrite loomist, lihtsustada konfiguratsiooni ja automateerida hooldust. Ilma lÀhtekoodita oleks seda palju keerulisem ja kÀtƥiaduslikum teha.
KĂ€esolevalt töötame teiste meie salvestussĂŒsteemide pilve ĂŒleviimise kallal â kuid see on juba hoopis teine lugu.
Allikas: habr.com
