NewSQL = NoSQL+ACIDO

NewSQL = NoSQL+ACIDO
Ĝis antaŭ nelonge, Odnoklassniki konservis ĉirkaŭ 50 TB da datumoj prilaboritaj en reala tempo en SQL-Servilo. Por tia volumo, estas preskaŭ neeble provizi rapidan kaj fidindan, kaj eĉ datumcentran malsukcesan aliron uzante SQL-DBMS. Tipe, en tiaj kazoj, unu el la NoSQL-stokado estas uzata, sed ne ĉio povas esti transdonita al NoSQL: iuj estaĵoj postulas ACID-transakciajn garantiojn.

Ĉi tio kondukis nin al la uzo de NewSQL-stokado, tio estas, DBMS kiu provizas misfunkciadon, skaleblon kaj rendimenton de NoSQL-sistemoj, sed samtempe konservante la ACID-garantiojn konatajn al klasikaj sistemoj. Estas malmultaj laborantaj industriaj sistemoj de ĉi tiu nova klaso, do ni mem efektivigis tian sistemon kaj metis ĝin en komercan operacion.

Kiel ĝi funkcias kaj kio okazis - legu sub la tranĉo.

Hodiaŭ, la monata spektantaro de Odnoklassniki estas pli ol 70 milionoj da unikaj vizitantoj. Ni Ni estas en la unuaj kvin plej grandaj sociaj retoj en la mondo, kaj inter la dudek retejoj sur kiuj uzantoj pasigas la plej multe da tempo. La OK-infrastrukturo pritraktas tre altajn ŝarĝojn: pli ol miliono da HTTP-petoj/sec per fronto. Partoj de servila aro de pli ol 8000 1 pecoj situas proksime unu al la alia - en kvar Moskvaj datumcentroj, kio ebligas retan latentecon de malpli ol XNUMX ms inter ili.

Ni uzas Cassandra ekde 2010, ekde la versio 0.6. Hodiaŭ ekzistas pluraj dekduoj de aretoj en operacio. La plej rapida areto procesas pli ol 4 milionojn da operacioj sekundo, kaj la plej granda stokas 260 TB.

Tamen ĉi tiuj estas ĉiuj ordinaraj NoSQL-aretoj uzataj por stokado malforte kunordigita datumoj. Ni volis anstataŭigi la ĉefan konsekvencan stokadon, Microsoft SQL Server, kiu estis uzata ekde la fondo de Odnoklassniki. La stokado konsistis el pli ol 300 maŝinoj SQL Server Standard Edition, kiuj enhavis 50 TB da datumoj - komercaj entoj. Ĉi tiuj datumoj estas modifitaj kiel parto de ACID-transakcioj kaj postulas alta konsistenco.

Por distribui datumojn tra SQL-Servilo-nodoj, ni uzis ambaŭ vertikalajn kaj horizontalajn dispartigo (dividado). Historie, ni uzis simplan datuman skemon: ĉiu ento estis asociita kun ĵetono - funkcio de la enta ID. Entoj kun la sama ĵetono estis metitaj sur la saman SQL-servilon. La mastro-detala rilato estis efektivigita tiel ke la ĵetonoj de la ĉefaj kaj infanaj rekordoj ĉiam kongruis kaj situis sur la sama servilo. En socia reto, preskaŭ ĉiuj rekordoj estas generitaj nome de la uzanto - kio signifas, ke ĉiuj uzantdatenoj ene de unu funkcia subsistemo estas stokitaj sur unu servilo. Tio estas, komerca transakcio preskaŭ ĉiam implikis tabelojn de unu SQL-servilo, kio ebligis certigi datuman konsistencon uzante lokajn ACID-transakciojn, sen la bezono uzi malrapida kaj nefidinda distribuitaj ACID-transakcioj.

Danke al sharding kaj akceli SQL:

  • Ni ne uzas fremdajn ŝlosillimojn, ĉar dum sharding la enta ID povas troviĝi sur alia servilo.
  • Ni ne uzas konservitajn procedurojn kaj ellasilon pro la plia ŝarĝo sur la DBMS-CPU.
  • Ni ne uzas JOIN-ojn pro ĉio ĉi-supra kaj multaj hazardaj legoj el disko.
  • Ekster transakcio, ni uzas la nivelon de izoliĝo de Read Uncommitted por redukti blokiĝon.
  • Ni faras nur mallongajn transakciojn (averaĝe pli mallongaj ol 100 ms).
  • Ni ne uzas plurvicajn UPDATE kaj DELETE pro la granda nombro da blokiĝo - ni ĝisdatigas nur unu rekordon samtempe.
  • Ni ĉiam faras demandojn nur pri indeksoj - konsulto kun plena skanplano por ni signifas troŝarĝi la datumbazon kaj igi ĝin malsukcesi.

Ĉi tiuj paŝoj permesis al ni elpremi preskaŭ maksimuman rendimenton el SQL-serviloj. Tamen, la problemoj fariĝis pli kaj pli multaj. Ni rigardu ilin.

Problemoj kun SQL

  • Ĉar ni uzis memskribitan sharding, aldoni novajn sharding estis farita permane de administrantoj. Dum ĉi tiu tempo, skaleblaj datumkopioj ne servis petojn.
  • Ĉar la nombro da rekordoj en la tabelo kreskas, la rapideco de enmeto kaj modifo malpliiĝas; kiam oni aldonas indeksojn al ekzistanta tabelo, la rapideco malpliiĝas je faktoro; kreado kaj rekreado de indeksoj okazas kun malfunkcio.
  • Havi malgrandan kvanton da Vindozo por SQL-Servilo en produktado malfaciligas infrastrukturan administradon

Sed la ĉefa problemo estas

kulpo toleremo

La klasika SQL-servilo havas malbonan faŭltoleremon. Ni diru, ke vi havas nur unu datumbazan servilon, kaj ĝi malsukcesas unufoje ĉiujn tri jarojn. Dum ĉi tiu tempo la retejo malfunkcias dum 20 minutoj, kio estas akceptebla. Se vi havas 64 servilojn, tiam la retejo malfunkcias unufoje ĉiujn tri semajnojn. Kaj se vi havas 200 servilojn, tiam la retejo ne funkcias ĉiusemajne. Ĉi tio estas problemo.

Kion oni povas fari por plibonigi la misfunkciadon de SQL-servilo? Vikipedio invitas nin konstrui tre havebla areto: kie en kazo de fiasko de iu el la komponantoj estas rezerva.

Ĉi tio postulas aron de multekostaj ekipaĵoj: multaj duobligoj, optika fibro, komuna stokado, kaj la inkludo de rezervo ne funkcias fidinde: ĉirkaŭ 10% de ŝanĝado finiĝas kun la fiasko de la rezerva nodo kiel trajno malantaŭ la ĉefa nodo.

Sed la ĉefa malavantaĝo de tia tre havebla areto estas nula havebleco se la datumcentro en kiu ĝi situas malsukcesas. Odnoklassniki havas kvar datumcentrojn, kaj ni devas certigi funkciadon en la okazo de kompleta fiasko en unu el ili.

Por tio ni povus uzi Multi-Majstro reproduktado konstruita en SQL-Servilon. Ĉi tiu solvo estas multe pli multekosta pro la kosto de programaro kaj suferas de konataj problemoj kun reproduktado - neantaŭvideblaj transakciaj prokrastoj kun sinkrona reproduktado kaj prokrastoj en aplikado de reproduktaĵoj (kaj, kiel rezulto, perditaj modifoj) kun nesinkrona reproduktado. La subkomprenata mana konfliktsolvado faras ĉi tiun opcion tute neaplikebla por ni.

Ĉiuj ĉi tiuj problemoj postulis radikalan solvon, kaj ni komencis detale analizi ilin. Ĉi tie ni devas konatiĝi kun tio, kion ĉefe faras SQL-Servilo - transakcioj.

Simpla transakcio

Ni konsideru la plej simplan transakcion, el la vidpunkto de aplikata SQL-programisto: aldoni foton al albumo. Albumoj kaj fotoj estas stokitaj en malsamaj platoj. La albumo havas publikan fotomontrilon. Tiam tia transakcio estas dividita en la sekvajn paŝojn:

  1. Ni ŝlosas la albumon per ŝlosilo.
  2. Kreu enskribon en la fototabelo.
  3. Se la foto havas publikan statuson, tiam aldonu publikan foto-nombrilon al la albumo, ĝisdatigu la rekordon kaj faru la transakcion.

Aŭ en pseŭdokodo:

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

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

TX.commit();

Ni vidas, ke la plej ofta scenaro por komerca transakcio estas legi datumojn de la datumbazo en la memoron de la aplika servilo, ŝanĝi ion kaj konservi la novajn valorojn reen al la datumbazo. Kutime en tia transakcio ni ĝisdatigas plurajn entojn, plurajn tabelojn.

Dum efektivigo de transakcio, samtempa modifo de la samaj datumoj de alia sistemo povas okazi. Ekzemple, Antispam povas decidi, ke la uzanto estas iel suspektema kaj tial ĉiuj fotoj de la uzanto ne plu estu publikaj, ili devas esti senditaj por modereco, kio signifas ŝanĝi photo.status al iu alia valoro kaj malŝalti la respondajn nombrilojn. Evidente, se ĉi tiu operacio okazas sen garantioj de atomeco de apliko kaj izolado de konkurantaj modifoj, kiel en ACIDO, tiam la rezulto ne estos la bezonata - aŭ la fota nombrilo montros la malĝustan valoron, aŭ ne ĉiuj fotoj estos senditaj por moderigo.

Multa simila kodo, manipulanta diversajn komercajn entojn ene de unu transakcio, estis skribitaj dum la tuta ekzisto de Odnoklassniki. Surbaze de la sperto de migradoj al NoSQL de Eventuala Konsistenco Ni scias, ke la plej granda defio (kaj tempa investo) venas de evoluigado de kodo por konservi datuman konsistencon. Tial ni konsideris la ĉefan postulon por la nova stokado esti provizo por realaj ACID-transakcioj por aplika logiko.

Aliaj, ne malpli gravaj, postuloj estis:

  • Se la datumcentro malsukcesas, ambaŭ legado kaj skribo al la nova stokado devas esti disponeblaj.
  • Konservante aktualan evolurapidecon. Tio estas, kiam oni laboras kun nova deponejo, la kvanto de kodo devus esti proksimume sama; ne devus esti aldoni ion ajn al la deponejo, evoluigi algoritmojn por solvi konfliktojn, konservi sekundarajn indeksojn, ktp.
  • La rapideco de la nova stokado devis esti sufiĉe alta, kaj dum legado de datumoj kaj dum prilaborado de transakcioj, kio efike signifis, ke akademie rigoraj, universalaj, sed malrapidaj solvoj, kiel ekzemple, ne estis aplikeblaj. dufazaj komitaĵoj.
  • Aŭtomata sur-la-muŝe skalo.
  • Uzante regulajn malmultekostajn servilojn, sen la bezono aĉeti ekzotikan aparataron.
  • Eblo de stokado-disvolviĝo fare de firmaaj programistoj. Alivorte, prioritato ricevis proprietajn aŭ malfermfontajn solvojn, prefere en Java.

Decidoj, decidoj

Analizante eblajn solvojn, ni venis al du eblaj arkitekturaj elektoj:

La unua estas preni ajnan SQL-servilon kaj efektivigi la bezonatan faŭltoleremon, skalmekanismon, malsukcesan areton, konfliktsolvon kaj distribuitajn, fidindajn kaj rapidajn ACID-transakciojn. Ni taksis ĉi tiun opcion kiel tre ne-triviala kaj laborintensa.

La dua opcio estas preni pretan NoSQL-stokadon kun efektivigita skalo, malsukcesa grapolo, konfliktsolvo, kaj efektivigi transakciojn kaj SQL mem. Unuavide, eĉ la tasko efektivigi SQL, sen mencii ACID-transakciojn, aspektas kiel tasko, kiu daŭros jarojn. Sed tiam ni rimarkis, ke la SQL-trajto-aro, kiun ni uzas en la praktiko, estas same malproksime de ANSI SQL kiel Kasandra CQL malproksime de ANSI SQL. Eĉ pli detale rigardante CQL, ni rimarkis, ke ĝi estas sufiĉe proksima al tio, kion ni bezonis.

Kasandra kaj CQL

Do, kio estas interesa pri Cassandra, kiajn kapablojn ĝi havas?

Unue, ĉi tie vi povas krei tabelojn kiuj subtenas diversajn datumtipojn; vi povas fari SELECT aŭ ĜISDATIGI sur la ĉefa ŝlosilo.

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

Por certigi kopiajn datumajn konsekvencon, Cassandra uzas kvoruma alproksimiĝo. En la plej simpla kazo, tio signifas, ke kiam tri kopioj de la sama vico estas metitaj sur malsamajn nodojn de la areto, la skribo estas konsiderata sukcesa se la plimulto de nodoj (tio estas, du el tri) konfirmis la sukceson de ĉi tiu skriboperacio. . La vico-datumoj estas konsiderataj konsekvencaj se, dum legado, la plimulto de nodoj estis enketitaj kaj konfirmitaj ilin. Tiel, kun tri kopioj, kompleta kaj tuja datenkonsistenco estas garantiita se unu nodo malsukcesas. Ĉi tiu aliro permesis al ni efektivigi eĉ pli fidindan skemon: ĉiam sendu petojn al ĉiuj tri kopioj, atendante respondon de la du plej rapidaj. La malfrua respondo de la tria kopio estas forĵetita en tiu kazo. Nodo kiu malfruas respondi povas havi gravajn problemojn - bremsoj, rubkolekto en la JVM, rekta memoro reakiro en la Linukso-kerno, aparataro fiasko, malkonekto de la reto. Tamen ĉi tio neniel influas la operaciojn aŭ datumojn de la kliento.

La aliro kiam ni kontaktas tri nodojn kaj ricevas respondon de du estas nomita spekulado: peto por ekstraj kopioj estas sendita eĉ antaŭ ol ĝi "falas".

Alia avantaĝo de Cassandra estas Batchlog, mekanismo kiu certigas ke aro de ŝanĝoj kiujn vi faras estas aŭ plene aplikataj aŭ tute ne aplikataj. Ĉi tio permesas al ni solvi A en ACIDO - atomeco el la skatolo.

La plej proksima al transakcioj en Kasandra estas la tiel nomataj "malpezaj transakcioj". Sed ili estas malproksime de "realaj" ACID-transakcioj: fakte, ĉi tio estas ŝanco por fari CAS pri datumoj de nur unu rekordo, uzante konsenton uzante la pezegulo Paxos-protokolon. Tial la rapideco de tiaj transakcioj estas malalta.

Kion ni mankis en Kasandra

Do, ni devis efektivigi realajn ACID-transakciojn en Kasandra. Uzante tion ni povus facile efektivigi du aliajn oportunajn funkciojn de klasika DBMS: konsekvencaj rapidaj indeksoj, kiuj permesus al ni plenumi datumajn elektojn ne nur per la primara ŝlosilo, kaj regula generatoro de monotonaj aŭto-incrementigaj identigiloj.

C*Unu

Tiel nova DBMS naskiĝis C*Unu, konsistante el tri specoj de servilnodoj:

  • Stokado - (preskaŭ) normaj Cassandra-serviloj respondecaj pri stokado de datumoj sur lokaj diskoj. Dum la ŝarĝo kaj volumo de datumoj kreskas, ilia kvanto povas esti facile skalita al dekoj kaj centoj.
  • Transakciaj kunordigantoj - certigas la plenumon de transakcioj.
  • Klientoj estas aplikaĵserviloj kiuj efektivigas komercajn operaciojn kaj iniciatas transakciojn. Povas ekzisti miloj da tiaj klientoj.

NewSQL = NoSQL+ACIDO

Serviloj de ĉiuj tipoj estas parto de komuna areto, uzas la internan Cassandra mesaĝprotokolo por komuniki unu kun la alia kaj ruzoj por interŝanĝi informojn pri grapo. Kun Heartbeat, serviloj lernas pri reciprokaj fiaskoj, konservas ununuran datumskemon - tabelojn, ilian strukturon kaj reproduktadon; dispartigoskemo, clustertopologio, ktp.

Klientoj

NewSQL = NoSQL+ACIDO

Anstataŭ normaj ŝoforoj, Fat Client-reĝimo estas uzata. Tia nodo ne konservas datumojn, sed povas funkcii kiel kunordiganto por ekzekuto de petoj, tio estas, la Kliento mem funkcias kiel kunordiganto de siaj petoj: ĝi pridemandas konservajn kopiojn kaj solvas konfliktojn. Ĉi tio ne nur estas pli fidinda kaj pli rapida ol la norma ŝoforo, kiu postulas komunikadon kun fora kunordiganto, sed ankaŭ permesas vin kontroli la transdonon de petoj. Ekster transakcio malfermita sur la kliento, petoj estas senditaj al deponejoj. Se la kliento malfermis transakcion, tiam ĉiuj petoj ene de la transakcio estas senditaj al la transakcia kunordiganto.
NewSQL = NoSQL+ACIDO

C*Unu Transakcia Kunordiganto

La kunordiganto estas io, kion ni efektivigis por C*One de nulo. Ĝi respondecas pri administrado de transakcioj, seruroj, kaj la ordo en kiu transakcioj estas aplikataj.

Por ĉiu servita transakcio, la kunordiganto generas tempomarkon: ĉiu posta transakcio estas pli granda ol la antaŭa transakcio. Ĉar la konfliktsolvosistemo de Kasandra estas bazita sur tempomarkoj (de du konfliktantaj rekordoj, tiu kun la plej lasta tempomarko estas konsiderita aktuala), la konflikto ĉiam estos solvita en favoro de la posta transakcio. Tiel ni efektivigis Horloĝo Lampport - malmultekosta maniero solvi konfliktojn en distribuita sistemo.

Kluzinstalaĵo

Por certigi izolitecon, ni decidis uzi la plej simplan metodon - pesimismajn serurojn bazitajn sur la ĉefa ŝlosilo de la rekordo. Alivorte, en transakcio, rekordo unue devas esti ŝlosita, nur poste legita, modifita kaj konservita. Nur post sukcesa transdono oni povas malŝlosi rekordon por ke konkurantaj transakcioj povu uzi ĝin.

Efektivigi tian ŝlosadon estas simpla en ne-distribuita medio. En distribuita sistemo, ekzistas du ĉefaj opcioj: aŭ efektivigi distribuitan ŝlosadon sur la areto, aŭ distribui transakciojn tiel ke transakcioj implikantaj la saman rekordon ĉiam estas servitaj fare de la sama kunordiganto.

Ĉar en nia kazo la datumoj jam estas distribuitaj inter grupoj de lokaj transakcioj en SQL, oni decidis atribui lokajn transakciajn grupojn al kunordigantoj: unu kunordiganto faras ĉiujn transakciojn kun ĵetonoj de 0 ĝis 9, la dua - kun ĵetonoj de 10 ĝis 19, kaj tiel plu. Kiel rezulto, ĉiu el la kunordigantoj iĝas la mastro de la transakciogrupo.

Tiam seruroj povas esti efektivigitaj en la formo de banala HashMap en la memoro de la kunordiganto.

Fiaskoj de kunordiganto

Ĉar unu kunordiganto ekskluzive servas grupon de transakcioj, estas tre grave rapide determini la fakton de ĝia malsukceso, por ke la dua provo efektivigi la transakcion forpasos. Por fari ĉi tion rapida kaj fidinda, ni uzis plene ligitan kvoruman aŭdbatan protokolon:

Ĉiu datumcentro gastigas almenaŭ du kunordigajn nodojn. Periode, ĉiu kunordiganto sendas korbatmesaĝon al la aliaj kunordigantoj kaj informas ilin pri ĝia funkciado, same kiel kiujn korbatmesaĝojn ĝi ricevis de kiuj kunordigantoj en la areto lastan fojon.

NewSQL = NoSQL+ACIDO

Ricevante similajn informojn de aliaj kiel parto de iliaj korbatmesaĝoj, ĉiu kunordiganto decidas por si kiuj aretnodoj funkcias kaj kiuj ne estas, gviditaj per la kvoruma principo: se nodo X ricevis informojn de la plimulto de nodoj en la areto pri la normalo. ricevo de mesaĝoj de nodo Y, tiam , Y funkcias. Kaj inverse, tuj kiam la plimulto raportas mankantajn mesaĝojn de nodo Y, tiam Y rifuzis. Estas kurioze, ke se la kvorumo informas la nodon X, ke ĝi ne plu ricevas mesaĝojn de ĝi, tiam la nodo X mem konsideros sin malsukcesinta.

Korbatmesaĝoj estas senditaj kun altfrekvenco, proksimume 20 fojojn je sekundo, kun periodo de 50 ms. En Java, estas malfacile garantii aplikaĵrespondon ene de 50 ms pro la komparebla longeco de paŭzoj kaŭzitaj de la rubkolektanto. Ni povis atingi ĉi tiun respondtempon uzante la rubkolektilon G1, kiu ebligas al ni specifi celon por la daŭro de GC-paŭzoj. Tamen, foje, sufiĉe malofte, la kolektanto paŭzoj superas 50 ms, kio povas konduki al malvera erara detekto. Por eviti ke tio okazu, la kunordiganto ne raportas malsukceson de la fora nodo kiam malaperas la unua korbatmesaĝo de ĝi, nur se malaperis pluraj sinsekve.Tiel ni sukcesis detekti la malsukceson de la kunordiga nodo en 200. ms.

Sed ne sufiĉas rapide kompreni, kiu nodo ĉesis funkcii. Ni devas fari ion pri tio.

Rezervado

La klasika skemo implikas, en la okazaĵo de majstra fiasko, komenci novan elekton uzante unu el moda universala algoritmoj. Tamen, tiaj algoritmoj havas konatajn problemojn kun tempokonverĝo kaj la longeco de la elektprocezo mem. Ni povis eviti tiajn pliajn malfruojn uzante kunordigan anstataŭan skemon en plene konektita reto:

NewSQL = NoSQL+ACIDO

Ni diru, ke ni volas efektivigi transakcion en la grupo 50. Ni determinu anticipe la anstataŭan skemon, tio estas, kiuj nodoj efektivigos transakciojn en la grupo 50 en la okazo de malsukceso de la ĉefa kunordiganto. Nia celo estas konservi sisteman funkciecon en la okazo de fiasko de datumcentro. Ni determinu, ke la unua rezervo estos nodo de alia datumcentro, kaj la dua rezervo estos nodo de tria. Ĉi tiu skemo estas elektita unufoje kaj ne ŝanĝiĝas ĝis la topologio de la areto ŝanĝiĝas, tio estas, ĝis novaj nodoj eniras ĝin (kio okazas tre malofte). La procedo por elekti novan aktivan majstron se la malnova malsukcesos ĉiam estos jena: la unua rezervo fariĝos la aktiva mastro, kaj se ĝi ĉesis funkcii, la dua rezervo fariĝos la aktiva majstro.

Ĉi tiu skemo estas pli fidinda ol la universala algoritmo, ĉar por aktivigi novan majstron sufiĉas determini la malsukceson de la malnova.

Sed kiel klientoj komprenos, kiu majstro laboras nun? Ne eblas sendi informojn al miloj da klientoj en 50 ms. Situacio eblas kiam kliento sendas peton por malfermi transakcion, ankoraŭ ne sciante, ke ĉi tiu majstro ne plu funkcias, kaj la peto eksvalidiĝos. Por malhelpi ĉi tion okazi, klientoj spekulative sendas peton malfermi transakcion al la grupestro kaj ambaŭ liaj rezervoj samtempe, sed nur tiu, kiu estas la aktiva mastro nuntempe, respondos al ĉi tiu peto. La kliento faros ĉiun postan komunikadon ene de la transakcio nur kun la aktiva mastro.

Rezervaj majstroj metas ricevitajn petojn por transakcioj, kiuj ne estas iliaj, en la vicon de nenaskitaj transakcioj, kie ili estas konservitaj dum iom da tempo. Se la aktiva majstro mortas, la nova majstro procesas petojn malfermi transakciojn de ĝia atendovico kaj respondas al la kliento. Se la kliento jam malfermis transakcion kun la malnova majstro, tiam la dua respondo estas ignorita (kaj, evidente, tia transakcio ne finiĝos kaj estos ripetita de la kliento).

Kiel funkcias la transakcio

Ni diru, ke kliento sendis peton al la kunordiganto malfermi transakcion por tia kaj tia ento kun tia kaj tia ĉefa ŝlosilo. La kunordiganto ŝlosas ĉi tiun enton kaj metas ĝin en la serurtabelon en memoron. Se necese, la kunordiganto legas ĉi tiun enton el stokado kaj konservas la rezultajn datumojn en transakcia stato en la memoro de la kunordiganto.

NewSQL = NoSQL+ACIDO

Kiam kliento volas ŝanĝi datumojn en transakcio, ĝi sendas peton al la kunordiganto por modifi la enton, kaj la kunordiganto metas la novajn datumojn en la transakcian statustabelon en memoron. Ĉi tio kompletigas la registradon - neniu registrado estas farita al la stokado.

NewSQL = NoSQL+ACIDO

Kiam kliento petas siajn proprajn ŝanĝitajn datumojn kiel parto de aktiva transakcio, la kunordiganto agas jene:

  • se la ID jam estas en la transakcio, tiam la datumoj estas prenitaj el memoro;
  • se ne estas identigilo en memoro, tiam la mankantaj datumoj estas legitaj de la stokaj nodoj, kombinitaj kun tiuj jam en memoro, kaj la rezulto estas donita al la kliento.

Tiel, la kliento povas legi siajn proprajn ŝanĝojn, sed aliaj klientoj ne vidas ĉi tiujn ŝanĝojn, ĉar ili estas konservitaj nur en la memoro de la kunordiganto; ili ankoraŭ ne estas en la nodoj Cassandra.

NewSQL = NoSQL+ACIDO

Kiam la kliento sendas kommit, la stato, kiu estis en la memoro de la servo, estas konservita de la kunordiganto en registrita aro, kaj estas sendita kiel registrita aro al Cassandra-stokado. La vendejoj faras ĉion necesan por certigi, ke ĉi tiu pako estas atome (tute) aplikata, kaj resendas respondon al la kunordiganto, kiu liberigas la serurojn kaj konfirmas la sukceson de la transakcio al la kliento.

NewSQL = NoSQL+ACIDO

Kaj por retroiri, la kunordiganto bezonas nur liberigi la memoron okupitan de la transakcia stato.

Kiel rezulto de ĉi-supraj plibonigoj, ni efektivigis la ACID-principojn:

  • Atomiko. Ĉi tio estas garantio, ke neniu transakcio estos parte registrita en la sistemo; aŭ ĉiuj ĝiaj suboperacioj estos kompletigitaj, aŭ neniu estos kompletigita. Ni aliĝas al ĉi tiu principo per registrita aro en Cassandra.
  • Kohereco. Ĉiu sukcesa transakcio, laŭ difino, registras nur validajn rezultojn. Se, post malfermi transakcion kaj plenumi parton de la operacioj, oni malkovras, ke la rezulto estas nevalida, oni realigas retrovon.
  • Izolo. Kiam transakcio estas efektivigita, samtempaj transakcioj ne devus influi ĝian rezulton. Konkurantaj transakcioj estas izolitaj uzante pesimismajn serurojn sur la kunordiganto. Por legoj ekster transakcio, la izolaj principo estas observita ĉe la Read Committed-nivelo.
  • Daŭripovo. Sendepende de problemoj ĉe pli malaltaj niveloj - sistemo senkurentiĝo, aparataro fiasko - ŝanĝoj faritaj de sukcese finita transakcio devus resti konservitaj kiam operacioj rekomencas.

Legado per indeksoj

Ni prenu simplan tabelon:

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

Ĝi havas identigilon (ĉefa ŝlosilo), posedanton kaj modifdaton. Vi devas fari tre simplan peton - elektu datumojn pri la posedanto kun la ŝanĝodato "por la lasta tago".

SELECT *
WHERE owner=?
AND modified>?

Por ke tia demando estu rapide procesita, en klasika SQL-DBMS vi devas konstrui indekson laŭ kolumnoj (posedanto, modifita). Ni povas fari tion sufiĉe facile, ĉar ni nun havas ACID-garantiojn!

Indeksoj en C*Unu

Estas fontotabelo kun fotoj en kiuj la rekorda ID estas la ĉefa ŝlosilo.

NewSQL = NoSQL+ACIDO

Por indekso, C*One kreas novan tabelon kiu estas kopio de la originalo. La ŝlosilo estas la sama kiel la indeksprimo, kaj ĝi ankaŭ inkluzivas la ĉefan ŝlosilon de la rekordo de la fonta tabelo:

NewSQL = NoSQL+ACIDO

Nun la demando por "posedanto por la lasta tago" povas esti reverkita kiel elekto el alia tabelo:

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

La konsistenco de la datumoj en la fontotabelfotoj kaj la indeksa tablo i1 estas konservita aŭtomate de la kunordiganto. Surbaze de la datuma skemo sole, kiam ŝanĝo estas ricevita, la kunordiganto generas kaj konservas ŝanĝon ne nur en la ĉefa tabelo, sed ankaŭ en kopioj. Neniuj aldonaj agoj estas faritaj sur la indeksa tabelo, protokoloj ne estas legitaj, kaj neniuj seruroj estas uzataj. Tio estas, aldoni indeksojn preskaŭ ne konsumas rimedojn kaj preskaŭ ne efikas sur la rapideco de aplikado de modifoj.

Uzante ACID, ni povis efektivigi SQL-similajn indeksojn. Ili estas konsekvencaj, skaleblaj, rapidaj, komponeblaj kaj enkonstruitaj en la CQL demandlingvo. Neniuj ŝanĝoj al aplika kodo estas postulataj por subteni indeksojn. Ĉio estas tiel simpla kiel en SQL. Kaj plej grave, indeksoj ne influas la ekzekutrapidecon de modifoj al la originala transakcia tablo.

Kio okazis

Ni evoluigis C*One antaŭ tri jaroj kaj lanĉis ĝin en komercan operacion.

Kion ni ricevis finfine? Ni taksu ĉi tion uzante la ekzemplon de la subsistemo de fototraktado kaj konservado, unu el la plej gravaj specoj de datumoj en socia reto. Ni ne parolas pri la korpoj de la fotoj mem, sed pri ĉiaj meta-informoj. Nun Odnoklassniki havas ĉirkaŭ 20 miliardojn da tiaj rekordoj, la sistemo prilaboras 80 mil legajn petojn sekundo, ĝis 8 mil ACID-transakcioj sekundo asociitaj kun datuma modifo.

Kiam ni uzis SQL kun replika faktoro = 1 (sed en RAID 10), la foto-metainformoj estis konservitaj sur tre havebla areto de 32 maŝinoj kurantaj Microsoft SQL Server (krom 11 sekurkopioj). 10 serviloj ankaŭ estis asignitaj por stokado de sekurkopioj. Entute 50 multekostaj aŭtoj. Samtempe, la sistemo funkciis kun taksita ŝarĝo, sen rezervo.

Post migrado al la nova sistemo, ni ricevis kopifaktoron = 3 - kopion en ĉiu datumcentro. La sistemo konsistas el 63 Cassandra stokadnodoj kaj 6 kunordigmaŝinoj, por entute 69 serviloj. Sed ĉi tiuj maŝinoj estas multe pli malmultekostaj, ilia totala kosto estas ĉirkaŭ 30% de la kosto de SQL-sistemo. Samtempe, la ŝarĝo estas konservita ĉe 30%.

Kun la enkonduko de C*One, latencia ankaŭ malpliiĝis: en SQL, skriboperacio daŭris proksimume 4,5 ms. En C*One - ĉirkaŭ 1,6 ms. La transakcia daŭro estas averaĝe malpli ol 40 ms, la kommit finiĝas en 2 ms, la legado kaj skriba daŭro estas averaĝe 2 ms. 99-a procento - nur 3-3,1 ms, la nombro da tempomalsukcesoj malpliiĝis je 100 fojojn - ĉio pro la disvastigita uzo de spekulado.

Nuntempe, la plej multaj el la SQL-Servilo-nodoj estis malmenditaj; novaj produktoj estas disvolvitaj nur per C*One. Ni adaptis C*One por labori en nia nubo unu-nubo, kiu ebligis akceli la disfaldiĝon de novaj aretoj, simpligi agordon kaj aŭtomatigi operacion. Sen la fontkodo, fari ĉi tion estus multe pli malfacila kaj maloportuna.

Nun ni laboras pri translokigo de niaj aliaj stokejoj al la nubo - sed tio estas tute alia historio.

fonto: www.habr.com

Aldoni komenton