Transakcioj en InterSystems IRIS-tutmondoj

Transakcioj en InterSystems IRIS-tutmondojLa InterSystems IRIS DBMS subtenas interesajn strukturojn por stokado de datumoj - tutmondaj. Esence, ĉi tiuj estas plurnivelaj ŝlosiloj kun diversaj pliaj bonaĵoj en formo de transakcioj, rapidaj funkcioj por trairi datumajn arbojn, serurojn kaj sian propran ObjectScript-lingvon.

Legu pli pri tutmondaj en la serio de artikoloj "Tutmondoj estas trezoraj glavoj por konservi datumojn":

Arboj. Parto 1
Arboj. Parto 2
Maldensaj tabeloj. Parto 3

Mi interesiĝis pri kiel transakcioj estas efektivigitaj en tutmondaj, kiaj funkcioj ekzistas. Post ĉio, ĉi tio estas tute malsama strukturo por stoki datumojn ol la kutimaj tabeloj. Multe pli malalta nivelo.

Kiel sciate de la teorio de interrilataj datumbazoj, bona efektivigo de transakcioj devas kontentigi la postulojn ACIDO:

A - Atomo (atomico). Ĉiuj ŝanĝoj faritaj en la transakcio aŭ neniuj estas registritaj.

C - Konsistenco. Post kiam transakcio finiĝas, la logika stato de la datumbazo devas esti interne konsekvenca. Multmaniere ĉi tiu postulo koncernas la programiston, sed en la kazo de SQL-datumbazoj ĝi koncernas ankaŭ fremdajn ŝlosilojn.

I - izoli. Transakcioj kurantaj paralele ne devus influi unu la alian.

D - Durable. Post sukcesa kompletigo de transakcio, problemoj ĉe pli malaltaj niveloj (ekzemple elektropaneo) ne devus influi la datumojn ŝanĝitajn de la transakcio.

Tutmondoj estas ne-rilataj datenstrukturoj. Ili estis dizajnitaj por funkcii super rapide sur tre limigita aparataro. Ni rigardu la efektivigon de transakcioj en tutmondaj uzante oficiala IRIS-docker-bildo.

Por subteni transakciojn en IRIS, la sekvaj komandoj estas uzataj: TSTART, TCOMMIT, TROLLBACK.

1. Atomiko

La plej facila maniero kontroli estas atomeco. Ni kontrolas el la datumbaza konzolo.

Kill ^a
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
TCOMMIT

Tiam ni konkludas:

Write ^a(1), “ ”, ^a(2), “ ”, ^a(3)

Ni ricevas:

1 2 3

Ĉio estas en ordo. Atomiko estas konservita: ĉiuj ŝanĝoj estas registritaj.

Ni malfaciligu la taskon, enkonduku eraron kaj vidu kiel la transakcio estas konservita, parte aŭ tute ne.

Ni kontrolu la atomecon denove:

Kill ^A
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3

Tiam ni forte haltigos la ujon, lanĉos ĝin kaj vidos.

docker kill my-iris

Ĉi tiu komando estas preskaŭ ekvivalenta al fortoĉesigo, ĉar ĝi sendas SIGKILL-signalon por ĉesigi la procezon tuj.

Eble la transakcio estis parte konservita?

WRITE ^a(1), ^a(2), ^a(3)
^
<UNDEFINED> ^a(1)

- Ne, ĝi ne pluvivis.

Ni provu la revuan komandon:

Kill ^A
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
TROLLBACK

WRITE ^a(1), ^a(2), ^a(3)
^
<UNDEFINED> ^a(1)

Ankaŭ nenio pluvivis.

2. Konsekvenco

Ĉar en datumbazoj bazitaj sur globaloj, ŝlosiloj ankaŭ estas faritaj sur globaloj (mi memorigu al vi, ke globalo estas pli malalta nivela strukturo por konservi datumojn ol interrilata tabelo), por plenumi la konsekvencan postulon, oni devas inkluzivi ŝanĝon en la ŝlosilo. en la sama transakcio kiel ŝanĝo en la tutmonda.

Ekzemple, ni havas tutmondan ^personon, en kiu ni konservas personecojn kaj ni uzas la TIN kiel ŝlosilon.

^person(1234567, ‘firstname’) = ‘Sergey’
^person(1234567, ‘lastname’) = ‘Kamenev’
^person(1234567, ‘phone’) = ‘+74995555555
...

Por havi rapidan serĉon laŭ familia nomo kaj antaŭnomo, ni faris la ^indeksklavon.

^index(‘Kamenev’, ‘Sergey’, 1234567) = 1

Por ke la datumbazo estu konsekvenca, ni devas aldoni la personon tiel:

TSTART
^person(1234567, ‘firstname’) = ‘Sergey’
^person(1234567, ‘lastname’) = ‘Kamenev’
^person(1234567, ‘phone’) = ‘+74995555555
^index(‘Kamenev’, ‘Sergey’, 1234567) = 1
TCOMMIT

Sekve, dum viŝado ni ankaŭ devas uzi transakcion:

TSTART
Kill ^person(1234567)
ZKill ^index(‘Kamenev’, ‘Sergey’, 1234567)
TCOMMIT

Alivorte, plenumi la konsekvencan postulon dependas tute sur la ŝultroj de la programisto. Sed se temas pri tutmondaj, tio estas normala, pro ilia malaltnivela naturo.

3. Izoliteco

Ĉi tie komenciĝas la sovaĝejoj. Multaj uzantoj samtempe laboras sur la sama datumbazo, ŝanĝante la samajn datumojn.

La situacio estas komparebla al kiam multaj uzantoj samtempe laboras kun la sama koda deponejo kaj provas samtempe fari ŝanĝojn al multaj dosieroj samtempe.

La datumbazo devus ordigi ĉion en reala tempo. Konsiderante, ke en seriozaj kompanioj ekzistas eĉ speciala persono, kiu respondecas pri versio-kontrolo (por kunfandi branĉojn, solvi konfliktojn, ktp.), kaj la datumbazo devas fari ĉion ĉi en reala tempo, la komplekseco de la tasko kaj la ĝusteco de la datumbaza dezajno kaj kodo kiu servas ĝin.

La datumbazo ne povas kompreni la signifon de la agoj faritaj de uzantoj por eviti konfliktojn se ili laboras pri la samaj datumoj. Ĝi povas nur malfari unu transakcion kiu konfliktas kun alia, aŭ efektivigi ilin sinsekve.

Alia problemo estas, ke dum la plenumo de transakcio (antaŭ kommit), la stato de la datumbazo povas esti malkonsekvenca, do estas dezirinde, ke aliaj transakcioj ne havu aliron al la malkonsekvenca stato de la datumbazo, kiu estas atingita en interrilataj datumbazoj. multmaniere: kreante momentfotojn, multi-versiajn vicojn ktp.

Kiam oni efektivigas transakciojn paralele, gravas por ni, ke ili ne malhelpas unu la alian. Ĉi tio estas la eco de izolado.

SQL difinas 4 izolaj niveloj:

  • LEGI SENDEGAĜI
  • LEGI COMPROMITETAS
  • RIPETEBLE LEGADO
  • SERIALIGebla

Ni rigardu ĉiun nivelon aparte. La kostoj de efektivigo de ĉiu nivelo kreskas preskaŭ eksponente.

LEGI SENDEGAĜI - ĉi tiu estas la plej malalta nivelo de izolado, sed samtempe la plej rapida. Transakcioj povas legi ŝanĝojn faritajn de unu la alian.

LEGI COMPROMITETAS estas la sekva nivelo de izolado, kiu estas kompromiso. Transakcioj ne povas legi la ŝanĝojn de unu la alian antaŭ la transdono, sed ili povas legi ajnajn ŝanĝojn faritajn post la transdono.

Se ni havas longan transakcion T1, dum kiu transakcioj okazis en transakcioj T2, T3 ... Tn, kiuj funkciis kun la samaj datumoj kiel T1, tiam kiam oni petas datumojn en T1, ni ricevos malsaman rezulton ĉiufoje. Tiu ĉi fenomeno nomiĝas neripetebla legado.

RIPETEBLE LEGADO — en ĉi tiu izoleca nivelo ni ne havas la fenomenon de neripetebla legado, pro tio, ke por ĉiu peto legi datumojn, estas kreita momentfoto de la rezultaj datumoj kaj kiam oni reuzas en la sama transakcio, la datumoj de la momentfoto. estas uzata. Tamen, eblas legi fantomajn datumojn sur ĉi tiu izoliteca nivelo. Ĉi tio rilatas al legado de novaj vicoj, kiuj estis aldonitaj per paralelaj transakcioj.

SERIALIGebla - la plej alta nivelo de izolado. Ĝi estas karakterizita per tio, ke datumoj uzataj iel ajn en transakcio (legado aŭ ŝanĝado) fariĝas disponeblaj por aliaj transakcioj nur post la kompletiĝo de la unua transakcio.

Unue, ni eltrovu ĉu estas izolado de operacioj en transakcio de la ĉefa fadeno. Ni malfermu 2 finajn fenestrojn.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Ne estas izolado. Unu fadeno vidas, kion faras la dua, kiu malfermis la transakcion.

Ni vidu ĉu transakcioj de malsamaj fadenoj vidas kio okazas en ili.

Ni malfermu 2 finajn fenestrojn kaj malfermu 2 transakciojn paralele.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

Paralelaj transakcioj vidas reciproke la datumojn de la alia. Do, ni akiris la plej simplan, sed ankaŭ la plej rapidan izolecan nivelon, LEGU SENDEGAĜI.

Principe, tio povus esti atendita por tutmondaj, por kiuj agado ĉiam estis prioritato.

Kio se ni bezonas pli altan izolitecon en operacioj sur tutmondaj?

Ĉi tie vi devas pensi pri kial entute necesas izolaj niveloj kaj kiel ili funkcias.

La plej alta izoliteca nivelo, SERIALIZE, signifas, ke la rezulto de transakcioj efektivigitaj paralele estas ekvivalenta al ilia sinsekva ekzekuto, kiu garantias la foreston de kolizioj.

Ni povas fari tion uzante inteligentajn serurojn en ObjectScript, kiuj havas multajn malsamajn uzojn: vi povas fari regulan, pliigan, multoblan ŝlosadon per la komando. LOCK.

Pli malaltaj izolaj niveloj estas kompromisoj dizajnitaj por pliigi datumbazrapidecon.

Ni vidu kiel ni povas atingi malsamajn nivelojn de izolado uzante serurojn.

Ĉi tiu funkciigisto permesas preni ne nur ekskluzivajn serurojn necesajn por ŝanĝi datumojn, sed tiel nomatajn komunajn serurojn, kiuj povas preni plurajn fadenojn paralele kiam ili bezonas legi datumojn, kiuj ne devus esti ŝanĝitaj de aliaj procezoj dum la legado.

Pliaj informoj pri la dufaza blokadmetodo en la rusa kaj la angla:

Dufaza blokado
Dufaza ŝlosado

La malfacileco estas, ke dum transakcio la stato de la datumbazo povas esti malkonsekvenca, sed ĉi tiuj malkonsekvencaj datumoj estas videblaj al aliaj procezoj. Kiel eviti ĉi tion?

Uzante serurojn, ni kreos videblajn fenestrojn en kiuj la stato de la datumbazo estos konsekvenca. Kaj ĉiu aliro al tiaj fenestroj de videbleco de la interkonsentita ŝtato estos kontrolita per seruroj.

Komunaj seruroj sur la samaj datumoj estas reuzeblaj - pluraj procezoj povas preni ilin. Ĉi tiuj seruroj malhelpas aliajn procezojn ŝanĝi datumojn, t.e. ili estas uzataj por formi fenestrojn de konsekvenca datumbaza stato.

Ekskluzivaj seruroj estas uzataj por datumŝanĝoj - nur unu procezo povas preni tian seruron. Ekskluziva seruro povas esti prenita de:

  1. Ajna procezo se la datumoj estas liberaj
  2. Nur la procezo kiu havas komunan seruro sur ĉi tiu datumo kaj estis la unua peti ekskluzivan seruro.

Transakcioj en InterSystems IRIS-tutmondoj

Ju pli mallarĝa estas la videbleco, des pli longaj aliaj procezoj devas atendi ĝin, sed des pli konsekvenca povas esti la stato de la datumbazo ene de ĝi.

READ_COMMITTED — la esenco de ĉi tiu nivelo estas, ke ni vidas nur faritajn datumojn de aliaj fadenoj. Se la datumoj en alia transakcio ankoraŭ ne estis faritaj, tiam ni vidas ĝian malnovan version.

Ĉi tio ebligas al ni paraleligi la laboron anstataŭ atendi ke la seruro estu liberigita.

Sen specialaj lertaĵoj, ni ne povos vidi la malnovan version de la datumoj en IRIS, do ni devos kontentiĝi per seruroj.

Sekve, ni devos uzi komunajn serurojn por permesi datumojn legi nur en momentoj de konsistenco.

Ni diru, ke ni havas uzantbazon ^personon, kiu transdonas monon unu al la alia.

Momento de translokigo de persono 123 al persono 242:

LOCK +^person(123), +^person(242)
Set ^person(123, amount) = ^person(123, amount) - amount
Set ^person(242, amount) = ^person(242, amount) + amount
LOCK -^person(123), -^person(242)

La momento de peti la monsumon de la persono 123 antaŭ ŝuldado devas esti akompanata de ekskluziva bloko (defaŭlte):

LOCK +^person(123)
Write ^person(123)

Kaj se vi bezonas montri la kontan staton en via persona konto, tiam vi povas uzi komunan seruron aŭ tute ne uzi ĝin:

LOCK +^person(123)#”S”
Write ^person(123)

Tamen, se ni supozas, ke datumbazaj operacioj estas faritaj preskaŭ tuj (mi memorigu al vi, ke globaloj estas multe pli malalta nivela strukturo ol interrilata tabelo), tiam la bezono de ĉi tiu nivelo malpliiĝas.

RIPETEBLE LEGADO - Ĉi tiu izoliteca nivelo permesas plurajn legadojn de datumoj, kiuj povas esti modifitaj per samtempaj transakcioj.

Sekve, ni devos meti komunan seruron por legi la datumojn, kiujn ni ŝanĝas, kaj ekskluzivajn serurojn sur la datumoj, kiujn ni ŝanĝas.

Feliĉe, la operatoro LOCK permesas vin listigi detale ĉiujn necesajn serurojn, el kiuj povas esti multaj, en unu deklaro.

LOCK +^person(123, amount)#”S”
чтение ^person(123, amount)

aliaj operacioj (nuntempe paralelaj fadenoj provas ŝanĝi ^person(123, kvanto), sed ne povas)

LOCK +^person(123, amount)
изменение ^person(123, amount)
LOCK -^person(123, amount)

чтение ^person(123, amount)
LOCK -^person(123, amount)#”S”

Kiam vi listigas serurojn apartigitajn per komoj, ili estas prenitaj sinsekve, sed se vi faras ĉi tion:

LOCK +(^person(123),^person(242))

tiam ili estas prenitaj atome samtempe.

SERIIGI — ni devos agordi serurojn, por ke finfine ĉiuj transakcioj, kiuj havas komunajn datumojn, estu plenumataj sinsekve. Por ĉi tiu aliro, la plej multaj seruroj devus esti ekskluzivaj kaj prenitaj sur la plej malgrandajn areojn de la tutmonda por agado.

Se ni parolas pri ŝuldado de fondusoj en la tutmonda ^persono, tiam nur la SERIALIZE-izola nivelo estas akceptebla por ĝi, ĉar mono devas esti elspezita strikte sinsekve, alie eblas elspezi la saman kvanton plurfoje.

4. Fortikeco

Mi faris provojn kun malmola tranĉado de la ujo uzante

docker kill my-iris

La bazo bone toleris ilin. Neniuj problemoj estis identigitaj.

konkludo

Por tutmonduloj, InterSystems IRIS havas transakcian subtenon. Ili estas vere atomaj kaj fidindaj. Por certigi konsistencon de datumbazo bazita sur globaloj, programistklopodoj kaj la uzo de transakcioj estas postulataj, ĉar ĝi ne havas kompleksajn enkonstruitajn konstrukciojn kiel ekzemple fremdaj ŝlosiloj.

La izoleca nivelo de globaloj sen uzado de seruroj estas LEGI NEENGAGITA, kaj kiam oni uzas serurojn ĝi povas esti certigita ĝis la SERIALIZE-nivelo.

La korekteco kaj rapideco de transakcioj sur tutmondaj tre dependas de la kapablo de la programisto: ju pli vaste komunaj seruroj estas uzataj dum legado, des pli alta estas la nivelo de izolado, kaj ju pli mallarĝe ekskluzivaj seruroj estas prenitaj, des pli rapide la agado.

fonto: www.habr.com

Aldoni komenton