InterSystems IRIS DBMS stÞtter interessante strukturer for lagring av data - globaler. I hovedsak er dette flernivÄnÞkler med diverse tilleggsgodbiter i form av transaksjoner, raske funksjoner for Ä krysse datatrÊr, lÄser og eget ObjectScript-sprÄk.
Les mer om globaler i artikkelserien «Globals er skattesverd for Ä lagre data»:
Jeg ble interessert i hvordan transaksjoner implementeres i globaler, hvilke funksjoner det er. Dette er tross alt en helt annen struktur for lagring av data enn de kjente tabellene. Mye lavere nivÄ.
Som kjent fra teorien om relasjonsdatabaser mÄ en god gjennomfÞring av transaksjoner tilfredsstille kravene :
A - Atomisk (atomisitet). Alle endringer som er gjort i transaksjonen eller ingen i det hele tatt blir registrert.
C - Konsistens. Etter at en transaksjon er fullfÞrt, mÄ den logiske tilstanden til databasen vÊre internt konsistent. PÄ mange mÄter gjelder dette kravet programmereren, men nÄr det gjelder SQL-databaser, gjelder det ogsÄ fremmednÞkler.
I - Isoler. Transaksjoner som gÄr parallelt bÞr ikke pÄvirke hverandre.
D - Slitesterk. Etter vellykket gjennomfÞring av en transaksjon skal problemer pÄ lavere nivÄer (for eksempel strÞmbrudd) ikke pÄvirke dataene som endres av transaksjonen.
Globaler er ikke-relasjonelle datastrukturer. De ble designet for Ä kjÞre superraskt pÄ svÊrt begrenset maskinvare. La oss se pÄ implementering av transaksjoner i globalt bruk .
For Ă„ stĂžtte transaksjoner i IRIS, brukes fĂžlgende kommandoer: , , .
1. Atomitet
Den enkleste mÄten Ä sjekke er atomitet. Vi sjekker fra databasekonsollen.
Kill ^a
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3
TCOMMITSĂ„ konkluderer vi:
Write ^a(1), â â, ^a(2), â â, ^a(3)Vi fĂ„r:
1 2 3Alt er bra. Atomiteten opprettholdes: alle endringer registreres.
La oss komplisere oppgaven, introdusere en feil og se hvordan transaksjonen lagres, delvis eller ikke i det hele tatt.
La oss sjekke atomiteten igjen:
Kill ^A
TSTART
Set ^a(1) = 1
Set ^a(2) = 2
Set ^a(3) = 3Da vil vi tvangsstanse containeren, lansere den og se.
docker kill my-irisDenne kommandoen tilsvarer nesten en kraftavstengning, da den sender et SIGKILL-signal for Ă„ stoppe prosessen umiddelbart.
Kanskje transaksjonen ble delvis lagret?
WRITE ^a(1), ^a(2), ^a(3)
^
<UNDEFINED> ^a(1)â Nei, den har ikke overlevd.
La oss prĂžve tilbakerullingskommandoen:
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)Ingenting har overlevd heller.
2. Konsistens
Siden i databaser basert pÄ globaler lages nÞkler ogsÄ pÄ globaler (la meg minne om at en global er en struktur pÄ lavere nivÄ for lagring av data enn en relasjonstabell), for Ä oppfylle konsistenskravet, mÄ en endring i nÞkkelen inkluderes i samme transaksjon som en endring i den globale.
For eksempel har vi en global ^person, der vi lagrer personligheter og vi bruker TIN som nĂžkkel.
^person(1234567, âfirstnameâ) = âSergeyâ
^person(1234567, âlastnameâ) = âKamenevâ
^person(1234567, âphoneâ) = â+74995555555
...For Ă„ ha et raskt sĂžk etter etternavn og fornavn, laget vi ^index-tasten.
^index(âKamenevâ, âSergeyâ, 1234567) = 1For at databasen skal vĂŠre konsistent, mĂ„ vi legge til persona slik:
TSTART
^person(1234567, âfirstnameâ) = âSergeyâ
^person(1234567, âlastnameâ) = âKamenevâ
^person(1234567, âphoneâ) = â+74995555555
^index(âKamenevâ, âSergeyâ, 1234567) = 1
TCOMMITFÞlgelig, nÄr vi sletter, mÄ vi ogsÄ bruke en transaksjon:
TSTART
Kill ^person(1234567)
ZKill ^index(âKamenevâ, âSergeyâ, 1234567)
TCOMMITà oppfylle konsistenskravet hviler med andre ord helt pÄ programmererens skuldre. Men nÄr det gjelder globaler, er dette normalt, pÄ grunn av deres lavnivÄ-natur.
3. Isolasjon
Det er her villmarken begynner. Mange brukere jobber samtidig pÄ den samme databasen, og endrer de samme dataene.
Situasjonen kan sammenlignes med nÄr mange brukere samtidig jobber med samme kodelager og prÞver Ä foreta endringer i mange filer samtidig.
Databasen skal sortere det hele i sanntid. Tatt i betraktning at i seriÞse selskaper er det til og med en spesiell person som er ansvarlig for versjonskontroll (for Ä slÄ sammen filialer, lÞse konflikter, etc.), og databasen mÄ gjÞre alt dette i sanntid, kompleksiteten til oppgaven og riktigheten av oppgaven. databasedesign og kode som tjener den.
Databasen kan ikke forstÄ betydningen av handlingene som utfÞres av brukere for Ä unngÄ konflikter hvis de jobber med samme data. Den kan bare angre en transaksjon som er i konflikt med en annen, eller utfÞre dem sekvensielt.
Et annet problem er at under utfÞrelsen av en transaksjon (fÞr en forpliktelse), kan tilstanden til databasen vÊre inkonsekvent, sÄ det er Þnskelig at andre transaksjoner ikke har tilgang til den inkonsistente tilstanden til databasen, som oppnÄs i relasjonsdatabaser pÄ mange mÄter: lage Þyeblikksbilder, multiversjonsrader og etc.
NÄr du utfÞrer transaksjoner parallelt, er det viktig for oss at de ikke forstyrrer hverandre. Dette er egenskapen til isolasjon.
SQL definerer 4 isolasjonsnivÄer:
- LES UENGASJERT
- LES ENGASJERT
- REPETERbar LES
- SERIALISERBAR
La oss se pÄ hvert nivÄ separat. Kostnadene ved Ä implementere hvert nivÄ vokser nesten eksponentielt.
LES UENGASJERT â dette er det laveste isolasjonsnivĂ„et, men samtidig det raskeste. Transaksjoner kan lese endringer gjort av hverandre.
LES ENGASJERT er neste nivÄ av isolasjon, som er et kompromiss. Transaksjoner kan ikke lese hverandres endringer fÞr commit, men de kan lese eventuelle endringer som er gjort etter commit.
Hvis vi har en lang transaksjon T1, hvor forpliktelser fant sted i transaksjonene T2, T3 ... Tn, som fungerte med de samme dataene som T1, vil vi nÄr vi ber om data i T1 fÄ et annet resultat hver gang. Dette fenomenet kalles ikke-repeterbar lesing.
REPETERbar LES â i dette isolasjonsnivĂ„et har vi ikke fenomenet ikke-repeterbar lesing, pĂ„ grunn av det faktum at for hver forespĂžrsel om Ă„ lese data, opprettes et Ăžyeblikksbilde av resultatdataene, og nĂ„r de gjenbrukes i samme transaksjon, dataene fra Ăžyeblikksbildet benyttes. Det er imidlertid mulig Ă„ lese fantomdata pĂ„ dette isolasjonsnivĂ„et. Dette refererer til Ă„ lese nye rader som ble lagt til av parallelle forpliktede transaksjoner.
SERIALISERBAR â hĂžyeste isolasjonsnivĂ„. Det er preget av det faktum at data som brukes pĂ„ noen mĂ„te i en transaksjon (lesing eller endring) blir tilgjengelig for andre transaksjoner fĂžrst etter fullfĂžringen av den fĂžrste transaksjonen.
FÞrst, la oss finne ut om det er isolasjon av operasjoner i en transaksjon fra hovedtrÄden. La oss Äpne 2 terminalvinduer.
Kill ^t
Write ^t(1)
2
TSTART
Set ^t(1)=2Det er ingen isolasjon. En trÄd ser hva den andre som Äpnet transaksjonen gjÞr.
La oss se om transaksjoner av forskjellige trÄder ser hva som skjer inne i dem.
La oss Äpne 2 terminalvinduer og Äpne 2 transaksjoner parallelt.
kill ^t
TSTART
Write ^t(1)
3
TSTART
Set ^t(1)=3
Parallelle transaksjoner ser hverandres data. SÄ vi fikk det enkleste, men ogsÄ det raskeste isolasjonsnivÄet, LES UENGASJERT.
I prinsippet kan dette forventes for globale, der ytelse alltid har vĂŠrt en prioritet.
Hva om vi trenger en hÞyere grad av isolasjon i operasjoner pÄ globale?
Her mÄ du tenke pÄ hvorfor isolasjonsnivÄer i det hele tatt trengs og hvordan de fungerer.
Det hÞyeste isolasjonsnivÄet, SERIALISERE, betyr at resultatet av transaksjoner utfÞrt parallelt tilsvarer deres sekvensielle utfÞrelse, noe som garanterer fravÊr av kollisjoner.
Vi kan gjÞre dette ved Ä bruke smarte lÄser i ObjectScript, som har mange forskjellige bruksomrÄder: du kan gjÞre vanlig, inkrementell, multippel lÄsing med kommandoen .
Lavere isolasjonsnivÄer er avveininger designet for Ä Þke databasehastigheten.
La oss se hvordan vi kan oppnÄ ulike nivÄer av isolasjon ved hjelp av lÄser.
Denne operatÞren lar deg ta ikke bare eksklusive lÄser som trengs for Ä endre data, men sÄkalte delte lÄser, som kan ta flere trÄder parallelt nÄr de skal lese data som ikke skal endres av andre prosesser under leseprosessen.
Mer informasjon om to-fase blokkeringsmetoden pÄ russisk og engelsk:
â
â
Vanskeligheten er at under en transaksjon kan tilstanden til databasen vÊre inkonsekvent, men disse inkonsekvente dataene er synlige for andre prosesser. Hvordan unngÄ dette?
Ved Ä bruke lÄser vil vi lage synlighetsvinduer der tilstanden til databasen vil vÊre konsistent. Og all tilgang til slike vinduer for synlighet av den avtalte staten vil bli kontrollert av lÄser.
Delte lĂ„ser pĂ„ de samme dataene kan gjenbrukes â flere prosesser kan ta dem. Disse lĂ„sene hindrer andre prosesser i Ă„ endre data, dvs. de brukes til Ă„ danne vinduer med konsistent databasetilstand.
Eksklusive lÄser brukes til dataendringer - kun én prosess kan ta en slik lÄs. En eksklusiv lÄs kan tas av:
- Enhver prosess hvis dataene er gratis
- Bare prosessen som har en delt lÄs pÄ disse dataene og var den fÞrste som ba om en eksklusiv lÄs.

Jo smalere synlighetsvinduet er, jo lenger mÄ andre prosesser vente pÄ det, men jo mer konsistent kan tilstanden til databasen i den vÊre.
READ_COMMITTED â essensen av dette nivĂ„et er at vi kun ser forpliktede data fra andre trĂ„der. Hvis dataene i en annen transaksjon ennĂ„ ikke er forpliktet, ser vi den gamle versjonen.
Dette gjÞr at vi kan parallellisere arbeidet i stedet for Ä vente pÄ at lÄsen skal frigjÞres.
Uten spesielle triks vil vi ikke kunne se den gamle versjonen av dataene i IRIS, sÄ vi mÄ nÞye oss med lÄser.
FÞlgelig mÄ vi bruke delte lÄser for Ä tillate at data kun kan leses i Þyeblikk med konsistens.
La oss si at vi har en brukerbase ^person som overfĂžrer penger til hverandre.
OverfĂžringstidspunkt fra person 123 til person 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)Ăyeblikket for Ă„ be om belĂžpet fra person 123 fĂžr debitering mĂ„ vĂŠre ledsaget av en eksklusiv blokkering (som standard):
LOCK +^person(123)
Write ^person(123)Og hvis du trenger Ä vise kontostatusen i din personlige konto, kan du bruke en delt lÄs eller ikke bruke den i det hele tatt:
LOCK +^person(123)#âSâ
Write ^person(123)Imidlertid, hvis vi antar at databaseoperasjoner utfÞres nesten umiddelbart (la meg minne deg pÄ at globaler er en struktur pÄ mye lavere nivÄ enn en relasjonstabell), sÄ reduseres behovet for dette nivÄet.
REPETERbar LES - Dette isolasjonsnivÄet gir mulighet for flere avlesninger av data som kan endres ved samtidige transaksjoner.
FÞlgelig mÄ vi sette en delt lÄs pÄ lesing av dataene vi endrer og eksklusive lÄser pÄ dataene vi endrer.
Heldigvis lar LOCK-operatÞren deg i detalj liste opp alle nÞdvendige lÄser, som det kan vÊre mye av, i en setning.
LOCK +^person(123, amount)#âSâ
ŃŃĐ”ĐœĐžĐ” ^person(123, amount)andre operasjoner (pĂ„ dette tidspunkt prĂžver parallelle trĂ„der Ă„ endre ^person(123, belĂžp), men kan ikke)
LOCK +^person(123, amount)
ĐžĐ·ĐŒĐ”ĐœĐ”ĐœĐžĐ” ^person(123, amount)
LOCK -^person(123, amount)
ŃŃĐ”ĐœĐžĐ” ^person(123, amount)
LOCK -^person(123, amount)#âSâNĂ„r du viser lĂ„ser atskilt med komma, tas de sekvensielt, men hvis du gjĂžr dette:
LOCK +(^person(123),^person(242))sÄ blir de tatt atomÊrt pÄ en gang.
serial â vi mĂ„ sette lĂ„ser slik at til syvende og sist alle transaksjoner som har felles data blir utfĂžrt sekvensielt. For denne tilnĂŠrmingen bĂžr de fleste lĂ„ser vĂŠre eksklusive og brukes pĂ„ de minste omrĂ„dene i verden for ytelse.
Hvis vi snakker om Ä debitere midler i den globale ^personen, er det bare SERIALISE-isolasjonsnivÄet som er akseptabelt for det, siden penger mÄ brukes strengt sekvensielt, ellers er det mulig Ä bruke samme belÞp flere ganger.
4. Holdbarhet
Jeg gjennomfĂžrte tester med hardkutting av beholderen vha
docker kill my-irisBasen tÄlte dem godt. Ingen problemer ble identifisert.
Konklusjon
For globale, har InterSystems IRIS transaksjonsstÞtte. De er virkelig atomÊre og pÄlitelige. For Ä sikre konsistens i en database basert pÄ globaler, kreves programmererinnsats og bruk av transaksjoner, siden den ikke har komplekse innebygde konstruksjoner som fremmednÞkler.
IsolasjonsnivĂ„et for globaler uten bruk av lĂ„ser er READ UNCOMMITED, og ââved bruk av lĂ„ser kan det sikres opp til SERIALISER-nivĂ„et.
Korrektheten og hastigheten til transaksjoner pÄ globaler avhenger veldig av ferdighetene til programmereren: jo mer utbredt delte lÄser som brukes under lesing, jo hÞyere isolasjonsnivÄ, og jo mer snevert eksklusive lÄser tas, jo raskere blir ytelsen.
Kilde: www.habr.com
