NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
Oant koartlyn bewarre Odnoklassniki sawat 50 TB oan gegevens ferwurke yn realtime yn SQL Server. Foar sa'n folume is it hast ûnmooglik om flugge en betroubere, en sels datacenter-fat-tolerante tagong te leverjen mei in SQL DBMS. Typysk wurdt yn sokke gefallen ien fan 'e NoSQL-opslach brûkt, mar net alles kin wurde oerdroegen oan NoSQL: guon entiteiten fereaskje ACID-transaksjegarânsjes.

Dit late ús ta it gebrûk fan NewSQL-opslach, dat is in DBMS dy't fouttolerânsje, skalberens en prestaasjes fan NoSQL-systemen leveret, mar tagelyk de ACID-garânsjes behâlden dy't bekend binne foar klassike systemen. D'r binne in pear wurkjende yndustriële systemen fan dizze nije klasse, dus hawwe wy sa'n systeem sels ymplementearre en yn kommersjele operaasje set.

Hoe't it wurket en wat der bard is - lês ûnder de besuniging.

Hjoed is it moanlikse publyk fan Odnoklassniki mear as 70 miljoen unike besikers. Wy Wy steane yn de top fiif grutste sosjale netwurken yn 'e wrâld, en ûnder de tweintich siden dêr't brûkers de measte tiid trochbringe. De OK-ynfrastruktuer behannelet heul hege loads: mear as in miljoen HTTP-oanfragen / sek per front. Dielen fan in serverfloat fan mear as 8000-stikken lizze tichtby elkoar - yn fjouwer Moskou datasintra, wêrtroch in netwurklatinsje fan minder dan 1 ms tusken har mooglik is.

Wy hawwe Cassandra sûnt 2010 brûkt, begjinnend mei ferzje 0.6. Tsjintwurdich binne der ferskate tsientallen klusters yn wurking. De fluchste kluster ferwurket mear as 4 miljoen operaasjes per sekonde, en de grutste winkels 260 TB.

Dit binne lykwols allegear gewoane NoSQL-klusters brûkt foar opslach swak koördinearre data. Wy woene de wichtichste konsekwinte opslach ferfange, Microsoft SQL Server, dy't sûnt de oprjochting fan Odnoklassniki is brûkt. De opslach bestie út mear as 300 SQL Server Standard Edition-masines, dy't 50 TB oan gegevens befette - saaklike entiteiten. Dizze gegevens wurde wizige as ûnderdiel fan ACID-transaksjes en fereasket hege konsistinsje.

Om gegevens te fersprieden oer SQL Server-knooppunten, brûkten wy sawol fertikaal as horizontaal ôfskieding (sjitten). Histoarysk brûkten wy in ienfâldich skema foar sharding fan gegevens: elke entiteit waard ferbûn mei in token - in funksje fan 'e entiteits-ID. Entiteiten mei deselde token waarden pleatst op deselde SQL-tsjinner. De master-detail-relaasje waard ymplementearre sadat de tokens fan 'e haad- en bernrecords altyd oerienkomme en op deselde server lizze. Yn in sosjaal netwurk wurde hast alle records generearre út namme fan 'e brûker - dat betsjut dat alle brûkersgegevens binnen ien funksjoneel subsysteem op ien server opslein wurde. Dat is, in saaklike transaksje befette hast altyd tabellen fan ien SQL-tsjinner, wat it mooglik makke om gegevenskonsistinsje te garandearjen mei lokale ACID-transaksjes, sûnder de needsaak om te brûken stadich en ûnbetrouber ferdield ACID transaksjes.

Mei tank oan sharding en om SQL te fersnellen:

  • Wy brûke gjin beheiningen foar bûtenlânske kaaien, om't by sharding de entiteits-ID op in oare tsjinner lizze kin.
  • Wy brûke gjin opsleine prosedueres en triggers fanwege de ekstra lading op 'e DBMS CPU.
  • Wy brûke gjin JOINs fanwege al it boppesteande en in protte willekeurich lêzen fan skiif.
  • Bûten in transaksje brûke wy it Read Uncommitted isolaasjenivo om deadlocks te ferminderjen.
  • Wy fiere allinich koarte transaksjes út (gemiddeld koarter dan 100 ms).
  • Wy brûke gjin UPDATE en DELETE mei meardere rigen fanwege it grutte oantal deadlocks - wy aktualisearje mar ien rekord tagelyk.
  • Wy fiere altyd queries allinich op yndeksen - in query mei in folsleine tabelscanplan foar ús betsjut dat de databank oerladen wurdt en dat it mislearret.

Dizze stappen lieten ús hast maksimale prestaasjes út SQL-tsjinners squeeze. De problemen waarden lykwols hieltyd mear. Litte wy nei se sjen.

Problemen mei SQL

  • Om't wy sels skreaune sharding brûkten, waard it tafoegjen fan nije shards manuell dien troch behearders. Al dy tiid wiene skalbere gegevensreplika's gjin oanfragen foar tsjinst.
  • As it oantal records yn 'e tabel groeit, nimt de snelheid fan ynfoegje en modifikaasje ôf; by it tafoegjen fan yndeksen oan in besteande tabel, sakket de snelheid mei in faktor; oanmeitsjen en opnij oanmeitsjen fan yndeksen komt foar mei downtime.
  • It hawwen fan in lyts bedrach fan Windows foar SQL Server yn produksje makket ynfrastruktuerbehear lestich

Mar it wichtichste probleem is

marzje foar flaters

De klassike SQL-tsjinner hat min fouttolerânsje. Litte wy sizze dat jo mar ien databanktsjinner hawwe, en it mislearret ien kear yn 'e trije jier. Yn dizze tiid is de side foar 20 minuten del, wat akseptabel is. As jo ​​​​64 tsjinners hawwe, dan is de side ien kear yn 'e trije wiken del. En as jo 200 servers hawwe, dan wurket de side net elke wike. Dit is probleem.

Wat kin dien wurde om de fouttolerânsje fan in SQL-tsjinner te ferbetterjen? Wikipedia noeget ús út om te bouwen heech beskikber kluster: wêr't yn gefal fan mislearring fan ien fan 'e komponinten in reservekopy is.

Dit fereasket in float fan djoere apparatuer: tal fan duplikaasjes, glêstried, dielde opslach, en it opnimmen fan in reserve wurket net betrouber: sa'n 10% fan skeakels einigje mei it mislearjen fan 'e reservekopyknooppunt as in trein efter de haadknooppunt.

Mar it wichtichste neidiel fan sa'n tige beskikber kluster is nul beskikberens as it datasintrum dêr't it yn sit, mislearret. Odnoklassniki hat fjouwer datasintra, en wy moatte soargje foar operaasje yn it gefal fan in folsleine mislearring yn ien fan harren.

Dêrfoar koene wy ​​brûke Multi-master replikaasje ynboud yn SQL Server. Dizze oplossing is folle djoerder fanwege de kosten fan software en lijt fan bekende problemen mei replikaasje - ûnfoarspelbere transaksjefertragingen mei syngroane replikaasje en fertragingen by it tapassen fan replikaasjes (en, as gefolch, ferlerne oanpassingen) mei asynchrone replikaasje. De ymplisearre hânmjittich konflikt oplossing makket dizze opsje folslein net fan tapassing foar ús.

Al dizze problemen easke in radikale oplossing, en wy begûn te analysearjen se yn detail. Hjir moatte wy yn 'e kunde komme mei wat SQL Server benammen docht - transaksjes.

Ienfâldige transaksje

Litte wy de ienfâldichste transaksje beskôgje, út it eachpunt fan in tapaste SQL-programmeur: in foto tafoegje oan in album. Albums en foto's wurde op ferskate platen opslein. It album hat in iepenbiere foto counter. Dan is sa'n transaksje ferdield yn de folgjende stappen:

  1. Wy beskoattelje it album troch de kaai.
  2. Meitsje in yngong yn de foto tabel.
  3. As de foto in iepenbiere status hat, foegje dan in iepenbiere fototeller ta oan it album, bywurkje de yngong en begean de transaksje.

Of yn pseudokoade:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

Wy sjogge dat it meast foarkommende senario foar in saaklike transaksje is om gegevens út 'e database te lêzen yn it ûnthâld fan' e applikaasjetsjinner, wat te feroarjen en de nije wearden werom te bewarjen yn 'e database. Meastal yn sa'n transaksje wy update ferskate entiteiten, ferskate tabellen.

By it útfieren fan in transaksje kin tagelyk wiziging fan deselde gegevens fan in oar systeem foarkomme. Bygelyks, Antispam kin beslute dat de brûker op ien of oare manier fertocht is en dêrom moatte alle foto's fan 'e brûker net mear iepenbier wêze, se moatte stjoerd wurde foar moderaasje, wat betsjut dat foto.status feroaret nei in oare wearde en de oerienkommende tellers losmeitsje. Fansels, as dizze operaasje bart sûnder garânsjes fan atomiteit fan tapassing en isolaasje fan konkurrearjende oanpassingen, lykas yn acid, dan sil it resultaat net wêze wat nedich is - of de fototeller sil de ferkearde wearde sjen litte, of net alle foto's wurde stjoerd foar moderaasje.

In protte ferlykbere koade, it manipulearjen fan ferskate saaklike entiteiten binnen ien transaksje, is skreaun yn it heule bestean fan Odnoklassniki. Op grûn fan 'e ûnderfining fan migraasjes nei NoSQL fan Eventuele Konsistinsje Wy witte dat de grutste útdaging (en tiid ynvestearring) komt fan it ûntwikkeljen fan koade om konsistinsje fan gegevens te behâlden. Dêrom beskôgen wy de wichtichste eask foar de nije opslach as foarsjenning foar echte ACID-transaksjes foar applikaasjelogika.

Oare, net minder wichtige easken wiene:

  • As it datasintrum mislearret, moatte sawol lêzen as skriuwen nei de nije opslach beskikber wêze.
  • Behâld fan hjoeddeistige ûntwikkelingssnelheid. Dat is, as jo wurkje mei in nij repository, moat it bedrach fan koade sawat itselde wêze; d'r soe gjin need nedich wêze om neat oan it repository ta te foegjen, algoritmen te ûntwikkeljen foar it oplossen fan konflikten, it behâld fan sekundêre yndeksen, ensfh.
  • De snelheid fan de nije opslach moast frij heech wêze, sawol by it lêzen fan gegevens as by it ferwurkjen fan transaksjes, wat effektyf betsjutte dat akademysk strange, universele, mar trage oplossingen, lykas bygelyks, net fan tapassing wiene twa-fase commits.
  • Automatysk on-the-fly skaalfergrutting.
  • Gebrûk fan gewoane goedkeape servers, sûnder de needsaak om eksoatyske hardware te keapjen.
  • Mooglikheid fan opslachûntwikkeling troch bedriuwsûntwikkelders. Mei oare wurden, prioriteit waard jûn oan proprietêre of iepen boarne oplossingen, leafst yn Java.

Besluten, besluten

Troch mooglike oplossingen te analysearjen, kamen wy ta twa mooglike kar foar arsjitektuer:

De earste is om elke SQL-tsjinner te nimmen en de fereaske fouttolerânsje, skaalmeganisme, failoverkluster, konfliktoplossing en ferspraat, betroubere en rappe ACID-transaksjes te ymplementearjen. Wy beoardiele dizze opsje as heul net-trivial en arbeidsintensyf.

De twadde opsje is om in klearmakke NoSQL-opslach te nimmen mei ymplementeare skaalfergrutting, in failover-kluster, konfliktoplossing, en sels transaksjes en SQL útfiere. Op it earste each liket sels de taak om SQL te ymplementearjen, net te hawwen oer ACID-transaksjes, as in taak dy't jierren duorje sil. Mar doe realisearre wy dat de SQL-funksjeset dy't wy yn 'e praktyk brûke is sa fier fan ANSI SQL as Cassandra CQL fier fan ANSI SQL. Troch noch mear nei CQL te sjen, realisearren wy dat it frij tichtby wie wat wy nedich wiene.

Cassandra en CQL

Dat, wat is nijsgjirrich oer Cassandra, hokker mooglikheden hat it?

As earste kinne jo hjir tabellen oanmeitsje dy't ferskate gegevenstypen stypje; jo kinne SELECT of UPDATE dwaan op 'e primêre kaai.

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

Om konsistinsje fan replika-gegevens te garandearjen, brûkt Cassandra quorum oanpak. Yn it ienfâldichste gefal betsjut dit dat by it pleatsen fan trije replika's fan deselde rige op ferskate knopen fan it kluster, it skriuwen wurdt beskôge as suksesfol as de mearderheid fan knopen (dus twa fan trije) it sukses fan dizze skriuwoperaasje befêstige. De gegevens fan in searje wurde as konsekwint beskôge as, by it lêzen, de mearderheid fan knooppunten waard ûndersocht en befêstige. Sa wurdt, mei trije replika's, folsleine en direkte gegevenskonsistinsje garandearre as ien knooppunt mislearret. Dizze oanpak liet ús in noch betrouberer skema útfiere: ferstjoere altyd fersiken nei alle trije replika's, wachtsjend op in antwurd fan 'e twa fluchste. De lette reaksje fan 'e tredde replika wurdt yn dit gefal wegere. In knooppunt dy't let is yn reagearjen kin serieuze problemen hawwe - remmen, garbage collection yn 'e JVM, direkte ûnthâld werom yn' e Linux-kernel, hardware-mislearring, disconnection fan it netwurk. Dit hat lykwols gjin ynfloed op de operaasjes of gegevens fan 'e kliïnt op ien of oare manier.

De oanpak as wy kontakt opnimme mei trije knopen en krije in antwurd fan twa wurdt neamd spekulaasje: in fersyk foar ekstra replika's wurdt ferstjoerd noch foardat it "ôffalt".

In oar foardiel fan Cassandra is Batchlog, in meganisme dat soarget dat in partij wizigingen dy't jo meitsje binne of folslein tapast of hielendal net tapast. Hjirmei kinne wy ​​A oplosse yn ACID - atomiteit út 'e doaze.

It tichtst by transaksjes yn Cassandra binne de saneamde "lichtgewicht transaksjes". Mar se binne fier fan "echte" ACID transaksjes: yn feite, dit is in kâns om te dwaan CAS oer gegevens fan mar ien rekord, mei konsensus mei it swiergewicht Paxos-protokol. Dêrom is de snelheid fan sokke transaksjes leech.

Wat wy misten yn Cassandra

Dat, wy moasten echte ACID-transaksjes ymplementearje yn Cassandra. Mei help fan dat kinne wy ​​maklik ymplemintearje twa oare handige funksjes fan klassike DBMS: konsekwinte snelle yndeksen, dy't soe tastean ús te fieren gegevens seleksjes net allinnich troch de primêre kaai, en in reguliere generator fan monotone auto-incrementing ID's.

C* ien

Sa is in nije DBMS berne C* ien, besteande út trije soarten serverknooppunten:

  • Storage - (hast) standert Cassandra tsjinners ferantwurdlik foar it bewarjen fan gegevens op lokale skiven. As de lading en it folume fan gegevens groeit, kin har kwantiteit maklik wurde skalearre nei tsientallen en hûnderten.
  • Transaksje koördinatoren - soargje foar de útfiering fan transaksjes.
  • Klanten binne applikaasjeservers dy't saaklike operaasjes útfiere en transaksjes begjinne. D'r kinne tûzenen fan sokke kliïnten wêze.

NewSQL = NoSQL+ACID

Servers fan alle soarten binne diel fan in mienskiplik kluster, brûke it ynterne Cassandra-berjochtprotokol om mei elkoar te kommunisearjen en berabje foar it útwikseljen fan klusterynformaasje. Mei Heartbeat learje tsjinners oer ûnderlinge mislearrings, ûnderhâlde in inkeld gegevensskema - tabellen, har struktuer en replikaasje; partitioneringsskema, klustertopology, ensfh.

Kliïnten

NewSQL = NoSQL+ACID

Yn stee fan standert bestjoerders wurdt Fat Client modus brûkt. Sa'n knooppunt bewarret gjin gegevens, mar kin fungearje as koördinator foar it útfieren fan oanfragen, dat is, de Klant sels fungearret as koördinator fan syn oanfragen: it freget opslachreplika's en lost konflikten op. Dit is net allinnich betrouber en flugger as de standert bestjoerder, dat fereasket kommunikaasje mei in ôfstân koördinator, mar ek kinne jo kontrolearje de oerdracht fan oanfragen. Bûten in transaksje iepen op 'e klant, wurde oanfragen stjoerd nei repositories. As de kliïnt in transaksje hat iepene, dan wurde alle oanfragen binnen de transaksje stjoerd nei de transaksjekoördinator.
NewSQL = NoSQL+ACID

C * One Transaction Coordinator

De koördinator is iets dat wy foar C * One fanôf it begjin ymplementearre hawwe. It is ferantwurdlik foar it behearen fan transaksjes, slûzen, en de folchoarder wêryn transaksjes wurde tapast.

Foar elke betsjinne transaksje genereart de koördinator in tiidstempel: elke folgjende transaksje is grutter dan de foarige transaksje. Sûnt Cassandra syn konflikt resolúsje systeem is basearre op timestamps (fan twa tsjinstridige records, de iene mei de lêste tiid stimpel wurdt beskôge aktueel), it konflikt sil altyd wurde oplost yn it foardiel fan de folgjende transaksje. Sa hawwe wy útfierd Lamport horloazje - in goedkeape manier om konflikten op te lossen yn in ferspraat systeem.

Slûzen

Om isolaasje te garandearjen, besletten wy de ienfâldichste metoade te brûken - pessimistyske slûzen basearre op 'e primêre kaai fan it rekord. Mei oare wurden, yn in transaksje moat in record earst beskoattele wurde, pas dan lêzen, wizige en bewarre. Allinich nei in suksesfolle commit kin in record wurde ûntskoattele sadat konkurrearjende transaksjes it kinne brûke.

It útfieren fan sa'n beskoatteljen is ienfâldich yn in net-ferdielde omjouwing. Yn in ferspraat systeem binne d'r twa haadopsjes: of ymplemintearje ferdielde beskoatteljen op it kluster, of distribúsje transaksjes sadat transaksjes mei deselde rekord altyd wurde betsjinne troch deselde koördinator.

Om't yn ús gefal de gegevens al ferdield binne ûnder groepen fan lokale transaksjes yn SQL, waard besletten om lokale transaksjegroepen oan koördinators te jaan: ien koördinator fiert alle transaksjes út mei tokens fan 0 oant 9, de twadde - mei tokens fan 10 oant 19, ensafuorthinne. As resultaat wurdt elk fan 'e koördinator-eksimplaren de master fan' e transaksjegroep.

Dan kinne slûzen wurde ymplementearre yn 'e foarm fan in banale HashMap yn it ûnthâld fan' e koördinator.

Koördinator mislearrings

Om't ien koördinator eksklusyf in groep transaksjes tsjinnet, is it heul wichtich om it feit fan syn mislearring fluch te bepalen, sadat de twadde besykjen om de transaksje út te fieren tiid út sil. Om dit rap en betrouber te meitsjen, hawwe wy in folslein ferbûn quorum hearbeat protokol brûkt:

Elk datasintrum host op syn minst twa koördinatorknooppunten. Periodyk stjoert elke koördinator in hertslachberjocht nei de oare koördinators en ynformearret harren oer it funksjonearjen, en ek hokker hertslachberjochten dy de lêste kear krigen hawwe fan hokker koördinators yn it kluster.

NewSQL = NoSQL+ACID

Troch ferlykbere ynformaasje te ûntfangen fan oaren as ûnderdiel fan har hertslachberjochten, beslút elke koördinator foar himsels hokker klusterknooppunten funksjonearje en hokker net, begelaat troch it quorumprinsipe: as knooppunt X ynformaasje hat krigen fan de mearderheid fan knopen yn it kluster oer de normale ûntfangst fan berjochten fan node Y, dan , Y wurket. En oarsom, sadree't de mearderheid meldt ûntbrekkende berjochten fan knooppunt Y, dan hat Y wegere. It is nijsgjirrich dat as it kworum knooppunt X ynformearret dat it der gjin berjochten mear fan ûntfangt, dan knooppunt X sels sil beskôgje dat it mislearre is.

Heartbeat-berjochten wurde ferstjoerd mei hege frekwinsje, sawat 20 kear per sekonde, mei in perioade fan 50 ms. Yn Java is it lestich om applikaasje-antwurd binnen 50 ms te garandearjen fanwegen de fergelykbere lingte fan pauzes feroarsake troch de garbage collector. Wy wienen by steat om te berikken dizze reaksje tiid mei help fan de G1 garbage collector, wêrtroch't wy kinne opjaan in doel foar de doer fan GC pauzes. Lykwols, soms, frij komselden, de samler pauzes mear as 50 ms, dat kin liede ta in falske fout detection. Om dat foar te kommen meldt de koördinator gjin falen fan in knooppunt op ôfstân as it earste hertslachberjocht derfan ferdwynt, allinnich as der ferskate efterinoar ferdwûn binne, sa hawwe wy yn 200 in mislearring fan it koördinatorknooppunt opspoard. ms.

Mar it is net genôch om fluch te begripen hokker knooppunt is stoppe mei funksjonearjen. Wy moatte hjir wat oan dwaan.

Reservaat

De klassike skema omfiemet, yn it gefal fan in master falen, begjinne in nije ferkiezing mei help fan ien fan moade universeel algoritmen. Sokke algoritmen hawwe lykwols bekende problemen mei tiidkonverginsje en de lingte fan it ferkiezingsproses sels. Wy koene sokke ekstra fertragingen foarkomme mei in koördinatorferfangingsskema yn in folslein ferbûn netwurk:

NewSQL = NoSQL+ACID

Litte wy sizze dat wy in transaksje wolle útfiere yn groep 50. Litte wy it ferfangende skema fan tefoaren bepale, dat is, hokker knooppunten transaksjes yn groep 50 útfiere yn gefal fan in mislearring fan 'e haadkoördinator. Us doel is om systeemfunksjonaliteit te behâlden yn gefal fan in datacenterfal. Litte wy bepale dat de earste reserve in knooppunt sil wêze fan in oar datasintrum, en de twadde reserve sil in knooppunt wêze fan in tredde. Dit skema wurdt ien kear selektearre en feroaret net oant de topology fan 'e kluster feroaret, dat is, oant nije knooppunten it ynfiere (wat tige seldsum bart). De proseduere foar it selektearjen fan in nije aktive master as de âlde mislearret sil altyd as folgjend wêze: de earste reserve sil de aktive master wurde, en as it net mear wurket, sil de twadde reserve de aktive master wurde.

Dit skema is betrouberer as it universele algoritme, om't in nije master te aktivearjen is genôch om it mislearjen fan 'e âlde te bepalen.

Mar hoe sille kliïnten begripe hokker master no wurket? It is ûnmooglik om ynformaasje te stjoeren nei tûzenen kliïnten yn 50 ms. In situaasje is mooglik as in kliïnt in fersyk stjoert om in transaksje te iepenjen, noch net te witten dat dizze master net mear funksjonearret, en it fersyk sil time-out. Om foar te kommen dat dit bart, stjoere kliïnten spekulatyf in fersyk om in transaksje te iepenjen nei de groepmaster en syn beide reserves tagelyk, mar allinich dejinge dy't op it stuit de aktive master is sil op dit fersyk reagearje. De kliïnt sil alle folgjende kommunikaasje binnen de transaksje allinich meitsje mei de aktive master.

Reservekopymasters pleatse ûntfongen oanfragen foar transaksjes dy't net harres binne yn 'e wachtrige fan ûnberne transaksjes, wêr't se in skoft opslein wurde. As de aktive master stjert, ferwurket de nije master fersiken om transaksjes út syn wachtrige te iepenjen en reagearret op de kliïnt. As de kliïnt al in transaksje mei de âlde master hat iepene, dan wurdt it twadde antwurd negearre (en, fansels, sa'n transaksje sil net foltôgje en sil troch de kliïnt werhelle wurde).

Hoe't de transaksje wurket

Litte wy sizze dat in kliïnt in fersyk stjoerde nei de koördinator om in transaksje te iepenjen foar sa'n en sa'n entiteit mei sa'n en sa'n primêre kaai. De koördinator slút dizze entiteit en pleatst it yn 'e slottabel yn it ûnthâld. As it nedich is, de koördinator lêst dizze entiteit út opslach en bewarret de resultearjende gegevens yn in transaksje tastân yn it ûnthâld fan de koördinator.

NewSQL = NoSQL+ACID

As in kliïnt gegevens yn in transaksje feroarje wol, stjoert it in fersyk nei de koördinator om de entiteit te feroarjen, en de koördinator pleatst de nije gegevens yn 'e transaksjestatustabel yn it ûnthâld. Dit foltôget de opname - gjin opname wurdt makke nei de opslach.

NewSQL = NoSQL+ACID

As in klant syn eigen feroare gegevens as ûnderdiel fan in aktive transaksje freget, hannelet de koördinator as folget:

  • as de ID al yn 'e transaksje is, dan wurde de gegevens út it ûnthâld nommen;
  • as der gjin ID yn it ûnthâld, dan de ûntbrekkende gegevens wurdt lêzen út de opslach knopen, kombinearre mei dy al yn it ûnthâld, en it resultaat wurdt jûn oan de klant.

Sa kin de kliïnt syn eigen wizigingen lêze, mar oare kliïnten sjogge dizze wizigingen net, om't se allinich yn it ûnthâld fan 'e koördinator wurde opslein; se binne noch net yn 'e Cassandra-knooppunten.

NewSQL = NoSQL+ACID

As de kliïnt commit stjoert, wurdt de steat dy't yn it ûnthâld fan 'e tsjinst wie bewarre troch de koördinator yn in oanmelde batch, en wurdt stjoerd as in oanmelde batch nei Cassandra-opslach. De winkels dogge alles wat nedich is om te soargjen dat dit pakket atomysk (folslein) wurdt tapast, en jouwe in antwurd oan 'e koördinator, dy't de slûzen loslitte en it sukses fan' e transaksje befêstiget oan 'e kliïnt.

NewSQL = NoSQL+ACID

En om werom te draaien, hoecht de koördinator allinich it ûnthâld te befrijen dat beset is troch de transaksjestatus.

As gefolch fan 'e boppesteande ferbetteringen hawwe wy de ACID-prinsipes ymplementearre:

  • Atomiteit. Dit is in garânsje dat gjin transaksje foar in part opnommen wurdt yn it systeem; of al syn suboperaasjes sille wurde foltôge, of gjinien sil wurde foltôge. Wy hâlde ús oan dit prinsipe troch oanmelde batch yn Cassandra.
  • Konsistinsje. Elke suksesfolle transaksje, per definysje, registrearret allinich jildige resultaten. As, nei it iepenjen fan in transaksje en it útfieren fan in diel fan 'e operaasjes, wurdt ûntdutsen dat it resultaat ûnjildich is, wurdt in weromdraaie útfierd.
  • Isolaasje. As in transaksje wurdt útfierd, moatte tagelyk transaksjes de útkomst net beynfloedzje. Konkurrearjende transaksjes wurde isolearre mei pessimistyske slûzen op 'e koördinator. Foar lêzen bûten in transaksje wurdt it isolaasjeprinsipe waarnommen op it Read Committed-nivo.
  • Duorsumens. Nettsjinsteande problemen op legere nivo's - systeem blackout, hardware flater - feroarings makke troch in mei súkses foltôge transaksje moatte bliuwe bewarre as operaasjes opnij.

Lêzen troch yndeksen

Litte wy in ienfâldige tabel nimme:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

It hat in ID (primêre kaai), eigner en modifikaasjedatum. Jo moatte in heul ienfâldich fersyk meitsje - selektearje gegevens oer de eigner mei de feroaringsdatum "foar de lêste dei".

SELECT *
WHERE owner=?
AND modified>?

Om sa'n query fluch te ferwurkjen, moatte jo yn in klassike SQL DBMS in yndeks bouwe troch kolommen (eigner, wizige). Wy kinne dit frij maklik dwaan, om't wy no ACID-garânsjes hawwe!

Yndeksen yn C * One

D'r is in boarnetabel mei foto's wêryn de rekord-ID de primêre kaai is.

NewSQL = NoSQL+ACID

Foar in yndeks makket C * One in nije tabel dat is in kopy fan it orizjineel. De kaai is itselde as de yndeksekspresje, en it omfettet ek de primêre kaai fan it record út 'e boarnetabel:

NewSQL = NoSQL+ACID

No kin de query foar "eigner foar de lêste dei" wurde herskreaun as in seleksje út in oare tabel:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

De gearhing fan de gegevens yn 'e boarne tabel foto's en de yndeks tabel i1 wurdt ûnderhâlden automatysk troch de koördinator. Op grûn fan it gegevensskema allinich, as in feroaring wurdt ûntfongen, genereart en bewarret de koördinator in feroaring net allinich yn 'e haadtabel, mar ek yn kopyen. Gjin ekstra aksjes wurde útfierd op de yndeks tafel, logs wurde net lêzen, en gjin slûzen wurde brûkt. Dat is, it tafoegjen fan yndeksen ferbrûkt hast gjin boarnen en hat praktysk gjin effekt op de snelheid fan it tapassen fan wizigingen.

Mei ACID koene wy ​​SQL-like yndeksen ymplementearje. Se binne konsekwint, skalberber, fluch, komponibel, en ynboud yn 'e CQL-fraachtaal. Gjin wizigingen oan tapassingskoade binne nedich om yndeksen te stypjen. Alles is sa ienfâldich as yn SQL. En it wichtichste, yndeksen hawwe gjin ynfloed op de útfieringssnelheid fan wizigingen oan 'e orizjinele transaksjetabel.

Wat is der bart

Wy ûntwikkele C * One trije jier lyn en lansearre it yn kommersjele operaasje.

Wat hawwe wy op it lêst krigen? Litte wy dit evaluearje mei it foarbyld fan it subsysteem foar fotoferwurking en opslach, ien fan 'e wichtichste soarten gegevens yn in sosjaal netwurk. Wy hawwe it net oer de lichems fan de foto's sels, mar oer allerhanne meta-ynformaasje. No hat Odnoklassniki sa'n 20 miljard sokke records, it systeem ferwurket 80 tûzen lêsoanfragen per sekonde, oant 8 tûzen ACID-transaksjes per sekonde ferbûn mei gegevensmodifikaasje.

Doe't wy SQL brûkten mei replikaasjefaktor = 1 (mar yn RAID 10), waard de fotometa-ynformaasje opslein op in heul beskikber kluster fan 32 masines mei Microsoft SQL Server (plus 11 backups). 10 servers waarden ek tawiisd foar it opslaan fan backups. Yn totaal 50 djoere auto's. Tagelyk operearre it systeem by rated load, sûnder reserve.

Nei it migrearjen nei it nije systeem krigen wy replikaasjefaktor = 3 - in kopy yn elk datasintrum. It systeem bestiet út 63 Cassandra opslach knopen en 6 koördinator masines, foar in totaal fan 69 tsjinners. Mar dizze masines binne folle goedkeaper, har totale kosten binne sawat 30% fan 'e kosten fan in SQL-systeem. Tagelyk wurdt de lading op 30% hâlden.

Mei de yntroduksje fan C*One naam de latency ek ôf: yn SQL naam in skriuwoperaasje sa'n 4,5 ms. Yn C*One - sawat 1,6 ms. De transaksjedoer is gemiddeld minder dan 40 ms, de commit is foltôge yn 2 ms, de lês- en skriuwtiid is gemiddeld 2 ms. 99e percentiel - mar 3-3,1 ms, it oantal timeouts is mei 100 kear ôfnommen - allegear troch it wiidferspraat gebrûk fan spekulaasje.

Tsjintwurdich binne de measte SQL Server-knooppunten útskeakele; nije produkten wurde allinich ûntwikkele mei C * One. Wy hawwe C*One oanpast om yn ús wolk te wurkjen ien-wolk, dy't it mooglik makke om de ynset fan nije klusters te rapperjen, konfiguraasje te ferienfâldigjen en operaasje te automatisearjen. Sûnder de boarnekoade soe dit dwaan folle dreger en omslachtiger wêze.

No wurkje wy oan it oerdragen fan ús oare opslachfoarsjenningen nei de wolk - mar dat is in folslein oar ferhaal.

Boarne: www.habr.com

Add a comment