Darījumi InterSystems IRIS globals

Darījumi InterSystems IRIS globalsInterSystems IRIS DBVS atbalsta interesantas datu glabāšanas struktūras - globālos. Būtībā tās ir daudzlīmeņu atslēgas ar dažādiem papildu labumiem transakciju veidā, ātrām funkcijām datu koku šķērsošanai, slēdzenes un savu ObjectScript valodu.

Vairāk par globāliem lasiet rakstu sērijā “Globāli ir dārgumu zobeni datu glabāšanai”:

Koki. 1. daļa
Koki. 2. daļa
Reti masīvi. 3. daļa

Sāku interesēties, kā globalos tiek realizēti darījumi, kādas tur ir iespējas. Galu galā šī ir pilnīgi atšķirīga datu glabāšanas struktūra nekā parastās tabulas. Daudz zemāks līmenis.

Kā zināms no relāciju datu bāzu teorijas, labai transakciju ieviešanai ir jāatbilst prasībām ACID:

A - Atomiskais (atomiskums). Tiek reģistrētas visas darījumā veiktās izmaiņas vai tās nav vispār.

C – konsekvence. Pēc darījuma pabeigšanas datu bāzes loģiskajam stāvoklim jābūt iekšēji konsekventam. Daudzējādā ziņā šī prasība attiecas uz programmētāju, bet SQL datu bāzu gadījumā tā attiecas arī uz ārējām atslēgām.

Es - Izolēt. Paralēli veiktie darījumi nedrīkst ietekmēt viens otru.

D - Izturīgs. Pēc veiksmīgas darījuma pabeigšanas problēmām zemākos līmeņos (piemēram, strāvas padeves pārtraukums) nevajadzētu ietekmēt datus, kas mainīti darījuma rezultātā.

Globālie ir nerelāciju datu struktūras. Tie tika izstrādāti, lai darbotos īpaši ātri ar ļoti ierobežotu aparatūru. Apskatīsim transakciju ieviešanu globalos, izmantojot oficiālais IRIS dokera attēls.

Lai atbalstītu darījumus IRIS, tiek izmantotas šādas komandas: TSTART, PASŪTĪT, TROLLBACK.

1. Atomiskums

Vienkāršākais veids, kā pārbaudīt atomitāti. Mēs pārbaudām no datu bāzes konsoles.

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

Tad mēs secinām:

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

Mēs iegūstam:

1 2 3

Viss ir kārtībā. Atomiskums tiek saglabāts: visas izmaiņas tiek reģistrētas.

Sarežģīsim uzdevumu, ievadīsim kļūdu un redzēsim, kā darījums tiek saglabāts daļēji vai vispār netiek saglabāts.

Vēlreiz pārbaudīsim atomitāti:

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

Tad mēs ar spēku apturēsim konteineru, palaidīsim to un redzēsim.

docker kill my-iris

Šī komanda ir gandrīz līdzvērtīga piespiedu izslēgšanai, jo tā nosūta SIGKILL signālu, lai nekavējoties apturētu procesu.

Varbūt darījums tika daļēji saglabāts?

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

- Nē, tas nav izdzīvojis.

Izmēģināsim atgriešanas komandu:

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)

Arī nekas nav saglabājies.

2. Konsekvence

Tā kā datu bāzēs, kuru pamatā ir globālās vērtības, atslēgas tiek veidotas arī uz globālajām (atgādināšu, ka globālā ir zemāka līmeņa struktūra datu glabāšanai nekā relāciju tabula), lai izpildītu konsekvences prasību, ir jāiekļauj atslēgas izmaiņas. tajā pašā darījumā kā izmaiņas globālajā.

Piemēram, mums ir globāla ^persona, kurā mēs glabājam personības un kā atslēgu izmantojam TIN.

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

Lai ātri meklētu pēc uzvārda un vārda, mēs izveidojām taustiņu ^index.

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

Lai datu bāze būtu konsekventa, persona jāpievieno šādi:

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

Attiecīgi, dzēšot, mums ir jāizmanto arī darījums:

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

Citiem vārdiem sakot, konsekvences prasības izpilde pilnībā gulstas uz programmētāja pleciem. Bet, runājot par globālajiem, tas ir normāli to zemā līmeņa dēļ.

3. Izolācija

Šeit sākas savvaļas dabas. Daudzi lietotāji vienlaikus strādā pie vienas datu bāzes, mainot vienus un tos pašus datus.

Situācija ir salīdzināma ar situāciju, kad daudzi lietotāji vienlaikus strādā ar vienu un to pašu kodu krātuvi un mēģina vienlaikus veikt izmaiņas daudzos failos vienlaikus.

Datubāzei tas viss ir jāsakārto reāllaikā. Ņemot vērā, ka nopietnos uzņēmumos ir pat īpašs cilvēks, kas atbild par versiju kontroli (par filiāļu apvienošanu, konfliktu risināšanu u.c.), un datu bāzei tas viss jādara reāllaikā, uzdevuma sarežģītība un pareizība. datu bāzes dizains un kods, kas to apkalpo.

Datubāze nevar saprast lietotāju veikto darbību nozīmi, lai izvairītos no konfliktiem, ja viņi strādā ar tiem pašiem datiem. Tas var atsaukt tikai vienu darījumu, kas ir pretrunā ar citu, vai izpildīt tos secīgi.

Problēma ir arī tā, ka darījuma izpildes laikā (pirms commit) datu bāzes stāvoklis var būt nekonsekvents, tāpēc vēlams, lai citiem darījumiem nebūtu pieejams datu bāzes nekonsekventais stāvoklis, kas tiek panākts relāciju datu bāzēs. daudzos veidos: veidojot momentuzņēmumus, vairākas versijas rindas utt.

Veicot darījumus paralēli, mums ir svarīgi, lai tie netraucētu viens otram. Šī ir izolācijas īpašība.

SQL definē 4 izolācijas līmeņus:

  • LASI NEKĀRTOTI
  • LASĪT SAISTĪTU
  • ATKĀRTOTI LASĪJUMS
  • SERIALIZĒJAMS

Apskatīsim katru līmeni atsevišķi. Katra līmeņa ieviešanas izmaksas pieaug gandrīz eksponenciāli.

LASI NEKĀRTOTI - tas ir zemākais izolācijas līmenis, bet tajā pašā laikā ātrākais. Darījumos var lasīt viens otra veiktās izmaiņas.

LASĪT SAISTĪTU ir nākamais izolācijas līmenis, kas ir kompromiss. Darījumi nevar nolasīt viens otra izmaiņas pirms saistību izpildes, taču tās var lasīt visas izmaiņas, kas veiktas pēc saistību izpildes.

Ja mums ir ilgs darījums T1, kura laikā notika commits darījumos T2, T3 ... Tn, kas strādāja ar tiem pašiem datiem kā T1, tad pieprasot datus T1, mēs katru reizi iegūsim citu rezultātu. Šo parādību sauc par neatkārtojamu lasīšanu.

ATKĀRTOTI LASĪJUMS — šajā izolācijas līmenī mums nav neatkārtojamas nolasīšanas fenomena, jo katram datu nolasīšanas pieprasījumam tiek izveidots rezultāta datu momentuzņēmums un, atkārtoti izmantojot tajā pašā darījumā, momentuzņēmuma dati. tiek izmantots. Tomēr šajā izolācijas līmenī ir iespējams nolasīt fantoma datus. Tas attiecas uz jaunu rindu nolasīšanu, kas tika pievienotas paralēli veikto darījumu rezultātā.

SERIALIZĒJAMS — visaugstākais izolācijas līmenis. To raksturo fakts, ka dati, kas jebkādā veidā tiek izmantoti darījumā (nolasot vai mainot), kļūst pieejami citiem darījumiem tikai pēc pirmā darījuma pabeigšanas.

Vispirms noskaidrosim, vai darījuma operācijas ir izolētas no galvenā pavediena. Atvērsim 2 termināļa logus.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Nav izolācijas. Viens pavediens redz, ko dara otrs, kurš atvēra darījumu.

Paskatīsimies, vai dažādu pavedienu darījumi redz, kas notiek tajos.

Atvērsim 2 termināļa logus un paralēli atvērsim 2 darījumus.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

Paralēli darījumi redz viens otra datus. Tātad, mēs ieguvām vienkāršāko, bet arī ātrāko izolācijas līmeni, READ UNCOMMITED.

Principā to varētu sagaidīt globālajiem uzņēmumiem, kuriem sniegums vienmēr ir bijis prioritāte.

Ko darīt, ja mums ir nepieciešams augstāks izolācijas līmenis operācijās ar globālajiem objektiem?

Šeit jums ir jādomā par to, kāpēc izolācijas līmeņi vispār ir nepieciešami un kā tie darbojas.

Augstākais izolācijas līmenis SERIALIZE nozīmē, ka paralēli veikto darījumu rezultāts ir līdzvērtīgs to secīgajai izpildei, kas garantē sadursmju neesamību.

Mēs to varam izdarīt, izmantojot viedās slēdzenes ObjectScript, kurām ir daudz dažādu lietojumu: jūs varat veikt regulāru, pakāpenisku, vairāku bloķēšanu ar komandu LOCK.

Zemāks izolācijas līmenis ir kompromiss, kas paredzēts datu bāzes ātruma palielināšanai.

Apskatīsim, kā mēs varam sasniegt dažādus izolācijas līmeņus, izmantojot slēdzenes.

Šis operators ļauj paņemt ne tikai ekskluzīvas datu maiņai nepieciešamās slēdzenes, bet arī tā sauktās koplietotās slēdzenes, kas paralēli var aizņemt vairākus pavedienus, kad tiem nepieciešams nolasīt datus, kurus lasīšanas procesā nevajadzētu mainīt citiem procesiem.

Plašāka informācija par divfāžu bloķēšanas metodi krievu un angļu valodā:

Divfāžu bloķēšana
Divfāžu bloķēšana

Grūtības ir tādas, ka darījuma laikā datu bāzes stāvoklis var būt nekonsekvents, bet šie nekonsekventie dati ir redzami citiem procesiem. Kā no tā izvairīties?

Izmantojot slēdzenes, mēs izveidosim redzamības logus, kuros datu bāzes stāvoklis būs konsekvents. Un visa pieeja šādiem norunātā stāvokļa redzamības logiem tiks kontrolēta ar slēdzenēm.

Vienu un to pašu datu koplietotās slēdzenes ir atkārtoti izmantojamas — tos var izmantot vairāki procesi. Šīs slēdzenes neļauj citiem procesiem mainīt datus, t.i. tos izmanto konsekventa datu bāzes stāvokļa logu veidošanai.

Datu izmaiņām tiek izmantotas ekskluzīvas slēdzenes – šādu bloķēšanu var veikt tikai viens process. Ekskluzīvu slēdzeni var paņemt:

  1. Jebkurš process, ja dati ir bezmaksas
  2. Tikai process, kuram ir koplietota bloķēšana šiem datiem un kurš pirmais pieprasīja ekskluzīvu bloķēšanu.

Darījumi InterSystems IRIS globals

Jo šaurāks ir redzamības logs, jo ilgāk citiem procesiem tas jāgaida, bet jo konsekventāks var būt datu bāzes stāvoklis tajā.

READ_COMMITTED — šī līmeņa būtība ir tāda, ka mēs redzam tikai iegūtos datus no citiem pavedieniem. Ja dati citā darījumā vēl nav piesaistīti, mēs redzam tā veco versiju.

Tas ļauj mums paralēli veikt darbu, nevis gaidīt slēdzenes atbrīvošanu.

Bez īpašiem trikiem IRIS nevarēsim redzēt veco datu versiju, tāpēc nāksies iztikt ar slēdzenēm.

Attiecīgi mums būs jāizmanto koplietotās bloķēšanas, lai datus varētu nolasīt tikai konsekvences brīžos.

Pieņemsim, ka mums ir lietotāju bāze ^persona, kas pārskaita naudu viens otram.

Pārejas brīdis no personas 123 uz personu 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)

Naudas summas pieprasīšanas brīdim no personas 123 pirms norakstīšanas jāpievieno ekskluzīvs bloks (pēc noklusējuma):

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

Un, ja jums ir jāparāda konta statuss savā personīgajā kontā, varat izmantot koplietojamo slēdzeni vai to neizmantot vispār:

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

Taču, ja pieņemam, ka datubāzes darbības tiek veiktas gandrīz acumirklī (atgādināšu, ka globālie ir daudz zemāka līmeņa struktūra nekā relāciju tabula), tad nepieciešamība pēc šī līmeņa samazinās.

ATKĀRTOTI LASĪJUMS - Šis izolācijas līmenis ļauj vairākkārt nolasīt datus, kurus var mainīt, veicot vienlaikus darījumus.

Attiecīgi mums būs jābloķē mainīto datu lasīšana un ekskluzīvas bloķēšanas iespējas datiem, kurus mēs mainām.

Par laimi, LOCK operators ļauj detalizēti uzskaitīt visas nepieciešamās slēdzenes, kuru var būt ļoti daudz, vienā paziņojumā.

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

citas darbības (šobrīd paralēlie pavedieni mēģina mainīt ^person(123, summa), bet nevar)

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

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

Uzskaitot slēdzenes, kas atdalītas ar komatiem, tās tiek ņemtas secīgi, bet, ja to darāt:

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

tad tos ņem atomiski visus uzreiz.

SERIALIZĒT — mums būs jāiestata bloķēšana, lai galu galā visas transakcijas, kurām ir kopīgi dati, tiktu izpildītas secīgi. Lai izmantotu šo pieeju, lielākajai daļai slēdzeņu ir jābūt ekskluzīvām un veiktspējas nodrošināšanai tās jāizmanto vismazākajās pasaules vietās.

Ja runājam par līdzekļu norakstīšanu globālajā cilvēkā, tad tam ir pieņemams tikai SERIALIZE izolācijas līmenis, jo nauda jātērē stingri secīgi, pretējā gadījumā vienu un to pašu summu iespējams iztērēt vairākas reizes.

4. Izturība

Es veicu testus ar cietu konteinera griešanu, izmantojot

docker kill my-iris

Bāze tos labi panesa. Problēmas netika konstatētas.

Secinājums

Globālajiem klientiem InterSystems IRIS ir transakciju atbalsts. Tie ir patiesi atomiski un uzticami. Lai nodrošinātu uz globāliem datiem balstītas datubāzes konsekvenci, ir nepieciešamas programmētāja pūles un transakciju izmantošana, jo tai nav sarežģītu iebūvētu konstrukciju, piemēram, ārējās atslēgas.

Globālu izolācijas līmenis, neizmantojot slēdzenes, ir READ UNCOMMITED, un, izmantojot slēdzenes, to var nodrošināt līdz SERIALIZE līmenim.

Globālos transakciju pareizība un ātrums lielā mērā ir atkarīgs no programmētāja prasmes: jo plašāk tiek izmantotas lasīšanas laikā koplietotās slēdzenes, jo augstāks ir izolācijas līmenis un jo šaurāk tiek ņemtas ekskluzīvas slēdzenes, jo ātrāka ir veiktspēja.

Avots: www.habr.com

Pievieno komentāru