NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
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 oleme viie 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 madala kooskĂ”lastatuse 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 kĂ”rget kooskĂ”lastatust..

SQL Serveri andmete jaotamiseks sĂ”lmedesse kasutasime nii vertikaalset kui ka horisontaalset partitsioneerimist. (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 aeglaseid ja ebaturvalisi 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 kÔrge kÀttesaadavuse klaster: 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 Multi-Master 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 kĂ€sitsi konfliktide lahendamine 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:

  1. Lukustame albumi selle vÔtme jÀrgi.
  2. Loome kirje fotode tabelis.
  3. 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 ACID, 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 Eventual Consistency 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 kahefsaalset kinnitamist.
  • 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 Cassandra CQL 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 kvoorumi lĂ€henemistKĂ”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 spekulatsiooniks: 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 "kergekaalulised tehingud". Kuid nad on kaugel "pĂ€ris" ACID-tehingutest: tegelikult on see vĂ”imalus teha CAS 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.

NewSQL = NoSQL+ACID

KĂ”ik serverid, olenemata tĂŒĂŒbist, kuuluvad ĂŒhisesse klastrisse, kasutavad omavaheliseks suhtlemiseks sisemist sĂ”numite protokolli Cassandra ja gossip 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

NewSQL = NoSQL+ACID

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.
NewSQL = NoSQL+ACID

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 Lamporti kellad – 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.

NewSQL = NoSQL+ACID

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 moes ĂŒldiselt 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:

NewSQL = NoSQL+ACID

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.

NewSQL = NoSQL+ACID

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.

NewSQL = NoSQL+ACID

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.

NewSQL = NoSQL+ACID

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.

NewSQL = NoSQL+ACID

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.

NewSQL = NoSQL+ACID

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:

NewSQL = NoSQL+ACID

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. one-cloud, 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

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster