Transaksjes yn InterSystems IRIS globals

Transaksjes yn InterSystems IRIS globalsDe InterSystems IRIS DBMS stipet ynteressante struktueren foar it bewarjen fan gegevens - globalen. Yn essinsje binne dit toetsen op meardere nivo's mei ferskate ekstra guod yn 'e foarm fan transaksjes, snelle funksjes foar it trochrinnen fan gegevensbeammen, slûzen en in eigen ObjectScript-taal.

Lês mear oer globalen yn 'e searje artikels "Globalen binne skatswurden foar it opslaan fan gegevens":

Beammen. Diel 1
Beammen. Diel 2
Sparse arrays. Diel 3

Ik waard ynteressearre yn hoe't transaksjes wurde ymplementearre yn globalen, hokker funksjes d'r binne. Dit is ommers in folslein oare struktuer foar it bewarjen fan gegevens as de gewoane tabellen. Folle leger nivo.

Sa't bekend is út 'e teory fan relaasje databases, in goede útfiering fan transaksjes moat foldwaan oan de easken acid:

A - Atoom (atomiciteit). Alle wizigingen makke yn 'e transaksje of hielendal gjin wurde opnommen.

C - Konsistinsje. Nei't in transaksje foltôge is, moat de logyske steat fan 'e databank yntern konsistint wêze. Op in protte manieren giet dizze eask de programmeur, mar yn it gefal fan SQL-databases giet it ek om bûtenlânske kaaien.

I - Isolearje. Transaksjes dy't parallel rinne moatte inoar net beynfloedzje.

D - Duorsum. Nei suksesfolle foltôging fan in transaksje moatte problemen op legere nivo's (bygelyks stroomfalen) gjin ynfloed hawwe op de gegevens dy't troch de transaksje feroare binne.

Globalen binne net-relasjonele gegevensstruktueren. Se waarden ûntworpen om superrap te rinnen op heul beheinde hardware. Litte wy sjen nei de ymplemintaasje fan transaksjes yn globalen mei help fan offisjele IRIS docker ôfbylding.

Om transaksjes yn IRIS te stypjen, wurde de folgjende kommando's brûkt: TSTART, TCOMMIT, TROLLBACK.

1. Atomity

De maklikste manier om te kontrolearjen is atomiteit. Wy kontrolearje fan 'e databankkonsole.

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

Dan konkludearje wy:

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

Wy krije:

1 2 3

Alles is ynoarder. Atomiciteit wurdt hanthavene: alle feroarings wurde opnommen.

Litte wy de taak komplisearje, in flater ynfiere en sjen hoe't de transaksje wurdt bewarre, foar in part of hielendal net.

Litte wy de atomiteit nochris kontrolearje:

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

Dan sille wy de kontener mei geweld stopje, it lansearje en sjen.

docker kill my-iris

Dit kommando is hast lykweardich oan in krêft shutdown, om't it in SIGKILL-sinjaal stjoert om it proses fuortendaliks te stopjen.

Miskien waard de transaksje foar in part bewarre?

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

- Nee, it is net oerlibbe.

Litte wy it rollback-kommando besykje:

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)

Der is ek neat oerlibbe.

2. Konsistinsje

Om't yn databases basearre op globalen, kaaien ek makke wurde op globalen (lit my jo herinnerje dat in global in struktuer op legere nivo is foar it bewarjen fan gegevens as in relaasjetabel), om te foldwaan oan de konsistinsjeeasken, moat in feroaring yn 'e kaai opnommen wurde yn deselde transaksje as in feroaring yn 'e globale.

Wy hawwe bygelyks in globale ^persoan, wêryn wy persoanlikheden opslaan en wy de TIN as kaai brûke.

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

Om fluch sykjen op efternamme en foarnamme te hawwen, hawwe wy de ^index-kaai makke.

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

Om de databank konsekwint te wêzen, moatte wy de persona sa tafoegje:

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

Dêrom moatte wy by it wiskjen ek in transaksje brûke:

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

Mei oare wurden, it ferfoljen fan 'e konsistinsjeeask leit folslein op' e skouders fan 'e programmeur. Mar as it giet om globals, dit is normaal, fanwegen harren lege-nivo natuer.

3. Isolaasje

Dit is wêr't de wilds begjinne. In protte brûkers wurkje tagelyk oan deselde databank, en feroarje deselde gegevens.

De situaasje is te fergelykjen mei wannear't in protte brûkers tagelyk wurkje mei deselde koade-repository en besykje tagelyk wizigingen yn in protte bestannen tagelyk te dwaan.

De databank moat it allegear yn realtime sortearje. Yn betinken nommen dat yn serieuze bedriuwen sels in spesjale persoan is dy't ferantwurdlik is foar ferzjekontrôle (foar it fusearjen fan tûken, it oplossen fan konflikten, ensfh.), En de databank moat dit alles yn realtime dwaan, de kompleksiteit fan 'e taak en de krektens fan' e databankûntwerp en koade dy't it tsjinnet.

De databank kin de betsjutting net begripe fan 'e aksjes útfierd troch brûkers om konflikten te foarkommen as se oan deselde gegevens wurkje. It kin allinich ien transaksje ûngedien meitsje dy't yn konflikt is mei in oar, of se opfolgjend útfiere.

In oar probleem is dat by it útfieren fan in transaksje (foardat in commit) de steat fan 'e databank inkonsistint wêze kin, dus is it winsklik dat oare transaksjes gjin tagong hawwe ta de inkonsistinte steat fan' e databank, dy't berikt wurdt yn relationele databases op in protte manieren: snapshots meitsje, rigen mei meardere ferzjes en ensfh.

By it útfieren fan transaksjes parallel, is it wichtich foar ús dat se net bemuoie mei elkoar. Dit is it eigendom fan isolemint.

SQL definiearret 4 isolaasjenivo's:

  • LADS UNCOMMITTED
  • L COMMS YNTREE
  • REPEATABLE Lêze
  • SERIALIZABLE

Litte wy elk nivo apart sjen. De kosten foar it útfieren fan elk nivo groeie hast eksponentiell.

LADS UNCOMMITTED - dit is it leechste nivo fan isolemint, mar tagelyk it rapste. Transaksjes kinne wizigingen lêze dy't troch elkoar makke binne.

L COMMS YNTREE is it folgjende nivo fan isolemint, dat is in kompromis. Transaksjes kinne inoars wizigingen net lêze foar de commit, mar se kinne alle wizigingen lêze dy't makke binne nei de commit.

As wy in lange transaksje T1 hawwe, wêrby't commits plakfûnen yn transaksjes T2, T3 ... Tn, dy't wurke mei deselde gegevens as T1, dan sille wy by it oanfreegjen fan gegevens yn T1 elke kear in oar resultaat krije. Dit ferskynsel wurdt neamd net-repeatable lêzen.

REPEATABLE Lêze - yn dit isolaasjenivo hawwe wy net it ferskynsel fan net-repeatable lêzen, fanwege it feit dat foar elk fersyk om gegevens te lêzen, in momintopname fan 'e resultaatgegevens wurdt makke en as se opnij brûkt wurde yn deselde transaksje, de gegevens fan 'e momintopname is brûkt. It is lykwols mooglik om fantoomgegevens te lêzen op dit isolaasjenivo. Dit ferwiist nei it lêzen fan nije rigen dy't waarden tafoege troch parallel tawijd transaksjes.

SERIALIZABLE - it heechste nivo fan isolaasje. It wurdt karakterisearre troch it feit dat gegevens dy't op ien of oare manier brûkt wurde yn in transaksje (lêzen of feroarjen) allinich beskikber binne foar oare transaksjes nei it foltôgjen fan 'e earste transaksje.

Lit ús earst útfine oft d'r isolemint is fan operaasjes yn in transaksje fan 'e haadtried. Litte wy 2 terminalfinsters iepenje.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Der is gjin isolemint. Ien thread sjocht wat de twadde docht dy't de transaksje iepene.

Litte wy sjen as transaksjes fan ferskate triedden sjogge wat der binnen bart.

Litte wy 2 terminalfinsters iepenje en 2 transaksjes parallel iepenje.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

Parallelle transaksjes sjogge inoars gegevens. Dat, wy krigen it ienfâldichste, mar ek it rapste isolaasjenivo, LÊS UNCOMMITED.

Yn prinsipe koe dit wurde ferwachte foar globalen, dêr't prestaasjes altyd in prioriteit west hawwe.

Wat as wy in heger nivo fan isolemint nedich binne yn operaasjes op globalen?

Hjir moatte jo tinke oer wêrom't isolaasjenivo's überhaupt nedich binne en hoe't se wurkje.

It heechste isolaasjenivo, SERIALIZE, betsjut dat it resultaat fan parallel útfierde transaksjes lykweardich is oan har opfolgjende útfiering, dy't de ôfwêzigens fan botsingen garandearret.

Wy kinne dit dwaan mei tûke slûzen yn ObjectScript, dy't in protte ferskillende gebrûk hawwe: jo kinne regelmjittich, inkrementeel, meardere beskoatteljen dwaan mei it kommando SLÛS.

Legere isolaasjenivo's binne ôfwikselingen ûntworpen om databanksnelheid te ferheegjen.

Lit ús sjen hoe't wy kinne berikke ferskate nivo's fan isolemint mei help fan slûzen.

Dizze operator kinne jo nimme net allinnich eksklusive slûzen nedich om te feroarjen gegevens, mar saneamde dielde slûzen, dat kin nimme ferskate triedden yn parallel as se moatte lêze gegevens dy't moatte net feroare wurde troch oare prosessen tidens it lêzen proses.

Mear ynformaasje oer de metoade foar blokkearjen fan twa faze yn Russysk en Ingelsk:

Twa-fase blokkearjen
Twa-fase slot

De swierrichheid is dat by in transaksje de steat fan 'e databank inkonsistint wêze kin, mar dizze ynkonsistinte gegevens binne sichtber foar oare prosessen. Hoe kinne jo dit foarkomme?

Mei help fan slûzen sille wy sichtberens finsters meitsje wêryn de tastân fan 'e databank konsekwint sil wêze. En alle tagong ta sokke finsters fan sichtberens fan 'e ôfpraat steat sil wurde regele troch slûzen.

Dielde slûzen op deselde gegevens binne opnij te brûken - ferskate prosessen kinne se nimme. Dizze slûzen foarkomme dat oare prosessen gegevens feroarje, d.w.s. se wurde brûkt om finsters te foarmjen fan konsekwinte databankstatus.

Eksklusive slûzen wurde brûkt foar gegevens feroarings - mar ien proses kin nimme sa'n slûs. In eksklusyf slot kin wurde nommen troch:

  1. Elk proses as de gegevens fergees binne
  2. Allinne it proses dat hat in dielde slot op dizze gegevens en wie de earste dy't frege in eksklusive slot.

Transaksjes yn InterSystems IRIS globals

Hoe smeller it sichtberensfinster, hoe langer oare prosessen derop moatte wachtsje, mar hoe konsekwinter de tastân fan 'e databank dêryn kin wêze.

READ_COMMITTED - de essinsje fan dit nivo is dat wy allinich ynsette gegevens fan oare threads sjogge. As de gegevens yn in oare transaksje noch net binne ynset, dan sjogge wy de âlde ferzje.

Hjirmei kinne wy ​​it wurk parallelisearje yn stee fan te wachtsjen foar it loslitten fan it slot.

Sûnder spesjale trúkjes sille wy de âlde ferzje fan 'e gegevens net yn IRIS kinne sjen, dus sille wy it dwaan moatte mei slûzen.

Dêrtroch sille wy dielde slûzen moatte brûke om gegevens allinich te lêzen op mominten fan konsistinsje.

Litte wy sizze dat wy in brûkersbasis hawwe ^persoan dy't jild oan elkoar oermeitsje.

Momint fan oerdracht fan persoan 123 nei persoan 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)

It momint fan it oanfreegjen fan it bedrach jild fan persoan 123 foardat debiting moat wurde begelaat troch in eksklusyf blok (standert):

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

En as jo de akkountstatus moatte sjen litte yn jo persoanlike akkount, dan kinne jo in dielde slot brûke of it hielendal net brûke:

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

As wy lykwols oannimme dat databankoperaasjes hast daliks útfierd wurde (lit my jo herinnerje dat globalen in folle legere struktuer binne as in relaasjetabel), dan nimt de needsaak foar dit nivo ôf.

REPEATABLE Lêze - Dit isolaasjenivo soarget foar meardere lêzingen fan gegevens dy't kinne wurde wizige troch tagelyk transaksjes.

Dêrtroch sille wy in dielde slûs moatte pleatse by it lêzen fan de gegevens dy't wy feroarje en eksklusive slûzen op 'e gegevens dy't wy feroarje.

Gelokkich, de operator LOCK kinne jo in list yn detail alle nedige slûzen, dêr't der kin in soad, yn ien ferklearring.

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

oare operaasjes (op dit stuit besykje parallelle diskusjes ^persoan (123, bedrach) te feroarjen, mar kinne net)

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

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

By it opjaan fan slûzen skieden troch komma's, wurde se opienfolgjend nommen, mar as jo dit dogge:

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

dan wurde se yn ien kear atomysk nommen.

SERIELIZE - wy sille slûzen moatte ynstelle sadat úteinlik alle transaksjes dy't mienskiplike gegevens hawwe, sequentieel wurde útfierd. Foar dizze oanpak, de measte slûzen moatte wêze eksklusyf en nommen op 'e lytste gebieten fan' e globale foar prestaasjes.

As wy prate oer it debitearjen fan fûnsen yn 'e wrâldwide ^persoan, dan is allinich it SERIALIZE-isolaasjenivo dêrfoar akseptabel, om't jild strikt opfolgjend moat wurde bestege, oars is it mooglik om itselde bedrach ferskate kearen te besteegjen.

4. Duorsumens

Ik útfierd testen mei hurde cutting fan de kontener mei help fan

docker kill my-iris

De basis tolerearre se goed. Gjin problemen waarden identifisearre.

konklúzje

Foar globalen hat InterSystems IRIS transaksjestipe. Se binne wirklik atoom en betrouber. Om konsistinsje te garandearjen fan in databank basearre op globalen, binne programmeur-ynspanningen en it brûken fan transaksjes nedich, om't it gjin komplekse ynboude konstruksjes hat lykas bûtenlânske kaaien.

It isolaasjenivo fan globalen sûnder gebrûk fan slûzen is LÊS UNCOMMITED, en by it brûken fan slûzen kin it wurde garandearre oant it SERIALIZE-nivo.

De krektens en snelheid fan transaksjes op globals hinget in protte ôf fan 'e feardigens fan' e programmeur: de mear dielde slûzen wurde brûkt by it lêzen, hoe heger it nivo fan isolemint, en de mear smel eksklusive slûzen wurde nommen, de flugger de prestaasjes.

Boarne: www.habr.com

Add a comment