Transaksionet në InterSystems IRIS globals

Transaksionet në InterSystems IRIS globalsDBMS-ja IRIS e InterSystems mbështet struktura interesante të ruajtjes së të dhënave të quajtura globalë. Këto janë në thelb çelësa me shumë nivele me veçori të ndryshme shtesë, të tilla si transaksione, funksione të shpejta për të përshkuar pemët e të dhënave, kyçje dhe një gjuhë të patentuar ObjectScript.

Lexoni mĂ« shumĂ« rreth globalave nĂ« serinĂ« e artikujve "Globalat—shpatat e ruajtjes sĂ« tĂ« dhĂ«nave":

Pemë. Pjesa 1
Pemë. Pjesa 2
Vargje të rralla. Pjesa 3

U interesova se si zbatohen transaksionet nĂ« tabelat globale dhe cilat janĂ« veçoritĂ« e tyre. NĂ« fund tĂ« fundit, Ă«shtĂ« njĂ« strukturĂ« krejtĂ«sisht e ndryshme e ruajtjes sĂ« tĂ« dhĂ«nave nga tabelat e njohura. ËshtĂ« e njĂ« niveli shumĂ« mĂ« tĂ« ulĂ«t.

Siç dihet nga teoria e bazave të të dhënave relacionale, një implementim i mirë i transaksioneve duhet të përmbushë kërkesat ACID:

A — Atomik (atomitet). TĂ« gjitha ndryshimet e bĂ«ra nĂ« transaksion regjistrohen, ose asnjĂ«ra prej tyre.

C — KonsistencĂ«. Pasi tĂ« pĂ«rfundojĂ« njĂ« transaksion, gjendja logjike e bazĂ«s sĂ« tĂ« dhĂ«nave duhet tĂ« jetĂ« konsistente nga brenda. Kjo kĂ«rkesĂ« kryesisht i pĂ«rket programuesit, por nĂ« rastin e bazave tĂ« tĂ« dhĂ«nave SQL, kjo vlen edhe pĂ«r çelĂ«sat e huaj.

UnĂ« — Izoloj (izolim). Transaksionet qĂ« kryhen njĂ«kohĂ«sisht nuk duhet tĂ« ndikojnĂ« te njĂ«ra-tjetra.

D — I qĂ«ndrueshĂ«m. Pasi njĂ« transaksion tĂ« ketĂ« pĂ«rfunduar me sukses, problemet nĂ« nivele mĂ« tĂ« ulĂ«ta (pĂ«r shembull, ndĂ«rprerja e energjisĂ«) nuk duhet tĂ« ndikojnĂ« nĂ« tĂ« dhĂ«nat e modifikuara nga transaksioni.

Globalet janë struktura të dhënash jo-relacionale. Ato janë projektuar për të funksionuar jashtëzakonisht shpejt në harduer shumë të kufizuar. Le të hedhim një vështrim në zbatimin e transaksioneve në globalet duke përdorur imazhi zyrtar i IRIS Docker.

Për të mbështetur transaksionet në IRIS, përdoren komandat e mëposhtme: FILLIMI, TCOMMIT, TROLLBACK.

1. Atomiciteti

Mënyra më e lehtë për të kontrolluar atomizmin është nga konzola e bazës së të dhënave.

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

Pastaj nxjerrim një përfundim:

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

Ne marrim:

1 2 3

Gjithçka është në rregull. Atomiciteti është ruajtur: të gjitha ndryshimet u shkruan.

Le ta ndërlikojmë detyrën, të fusim një gabim dhe të shohim se si ruhet transaksioni, pjesërisht ose aspak.

Le ta kontrollojmë përsëri atomicitetin:

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

Pas kësaj, ne do ta ndalojmë me forcë enën, do ta ndezim dhe do të shohim.

docker kill my-iris

Ky komand është pothuajse ekuivalent me një fikje të detyruar, pasi dërgon një sinjal SIGKILL për të ndaluar menjëherë procesin.

Ndoshta transaksioni është ruajtur pjesërisht?

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

- Jo, nuk ka mbijetuar.

Le të provojmë komandën e rikthimit:

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)

Asgjë nuk ka mbijetuar gjithashtu.

2. Konsistenca

Meqenëse në bazat e të dhënave me bazë globale çelësat krijohen edhe në baza globale (mbani mend se një tabelë globale është një strukturë ruajtjeje të dhënash e nivelit më të ulët sesa një tabelë relacionale), për të përmbushur kërkesën e konsistencës, ndryshimi i çelësit duhet të përfshihet në të njëjtin transaksion si ndryshimi global.

Për shembull, kemi një ^person global, në të cilin ruajmë informacione personale dhe përdorim TIN-in si çelës.

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

Për të pasur një kërkim të shpejtë sipas mbiemrit dhe emrit, krijuam çelësin ^index.

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

Që baza e të dhënave të jetë konsistente, duhet të shtojmë personelin si më poshtë:

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

Prandaj, kur fshijmë, duhet të përdorim edhe një transaksion:

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

Me fjalë të tjera, përgjegjësia për të siguruar qëndrueshmërinë i takon tërësisht programuesit. Por kur bëhet fjalë për globalet, kjo është normale për shkak të natyrës së tyre të nivelit të ulët.

3. Izolimi

Këtu fillon kompleksiteti. Shumë përdorues punojnë njëkohësisht në të njëjtën bazë të dhënash, duke ndryshuar të njëjtat të dhëna.

Situata është e krahasueshme me atë kur shumë përdorues punojnë me të njëjtën depo kodi në të njëjtën kohë dhe përpiqen të kryejnë ndryshime në shumë skedarë menjëherë.

Baza e të dhënave duhet t'i trajtojë të gjitha këto në kohë reale. Duke marrë parasysh që kompanitë serioze kanë edhe një person të dedikuar përgjegjës për kontrollin e versioneve (bashkimi i degëve, zgjidhja e konflikteve, etj.), dhe baza e të dhënave duhet t'i trajtojë të gjitha këto në kohë reale, kompleksiteti i detyrës dhe rëndësia e projektimit të duhur të bazës së të dhënave dhe kodit që e mbështet atë bëhen të qarta.

Baza e të dhënave nuk mund ta kuptojë kuptimin e veprimeve të kryera nga përdoruesit për të parandaluar konfliktet nëse ata punojnë me të njëjtat të dhëna. Ajo mund të anulojë vetëm një transaksion që bie ndesh me një tjetër ose t'i ekzekutojë ato në mënyrë sekuenciale.

Një problem tjetër është se gjatë ekzekutimit të një transaksioni (para kryerjes), gjendja e bazës së të dhënave mund të jetë e paqëndrueshme, kështu që është e dëshirueshme që transaksionet e tjera të mos kenë qasje në gjendjen e paqëndrueshme të bazës së të dhënave, e cila arrihet në bazat e të dhënave relacionale në shumë mënyra: krijimi i pamjeve të çastit, multi-versionimi i rreshtave, etj.

Kur ekzekutohen transaksione paralelisht, është e rëndësishme që ato të mos ndërhyjnë me njëra-tjetrën. Kjo është veçori e izolimit.

SQL përcakton 4 nivele izolimi:

  • LEXONI PA ANGAZHIM
  • LEXO I ANGAZHUAR
  • LEXIM I PËRSËRITSHËM
  • SERIALIZUESHME

Le ta shqyrtojmë secilin nivel veç e veç. Kostot e zbatimit të secilit nivel rriten pothuajse në mënyrë eksponenciale.

LEXONI PA ANGAZHIM — Ky Ă«shtĂ« niveli mĂ« i ulĂ«t i izolimit, por edhe mĂ« i shpejti. Transaksionet mund tĂ« lexojnĂ« ndryshimet e njĂ«ri-tjetrit.

LEXO I ANGAZHUAR — Ky Ă«shtĂ« niveli tjetĂ«r i izolimit, i cili Ă«shtĂ« njĂ« kompromis. Transaksionet nuk mund tĂ« lexojnĂ« ndryshimet e njĂ«ri-tjetrit para njĂ« kryerjeje, por ato mund tĂ« lexojnĂ« çdo ndryshim tĂ« bĂ«rĂ« pas njĂ« kryerjeje.

Nëse kemi një transaksion T1 me vazhdimësi të gjatë, gjatë të cilit janë bërë kryerje në transaksionet T2, T3 dhe Tn, të cilat kanë punuar me të njëjtat të dhëna si T1, atëherë kur kërkojmë të dhëna në T1, do të marrim një rezultat të ndryshëm çdo herë. Ky fenomen quhet lexim i papërsëritshëm.

LEXIM I PËRSËRITSHËM — NĂ« kĂ«tĂ« nivel izolimi, nuk kemi fenomenin e leximeve tĂ« papĂ«rsĂ«ritshme, sepse pĂ«r çdo kĂ«rkesĂ« leximi, krijohet njĂ« pamje e tĂ« dhĂ«nave qĂ« rezultojnĂ«, dhe kur ripĂ«rdoren nĂ« tĂ« njĂ«jtin transaksion, pĂ«rdoren tĂ« dhĂ«nat nga pamja e shkurtĂ«r. MegjithatĂ«, nĂ« kĂ«tĂ« nivel izolimi, leximi i tĂ« dhĂ«nave fantom Ă«shtĂ« i mundur. Kjo i referohet leximit tĂ« rreshtave tĂ« rinj qĂ« janĂ« shtuar nga transaksione tĂ« kryera njĂ«kohĂ«sisht.

SERIALIZUESHME — niveli mĂ« i lartĂ« i izolimit. Karakterizohet nga fakti qĂ« tĂ« dhĂ«nat e pĂ«rdorura nĂ« njĂ« transaksion (tĂ« lexuara ose tĂ« modifikuara) bĂ«hen tĂ« disponueshme pĂ«r transaksione tĂ« tjera vetĂ«m pasi tĂ« pĂ«rfundojĂ« transaksioni i parĂ«.

Së pari, le të kuptojmë nëse operacionet në një transaksion janë të izoluara nga thread-i kryesor. Le të hapim dy dritare terminali.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Nuk ka izolim. Një fije shikon se çfarë po bën fija tjetër që hapi transaksionin.

Le të shohim nëse transaksionet në fije të ndryshme mund të shohin se çfarë po ndodh brenda tyre.

Le të hapim 2 dritare terminali dhe të hapim 2 transaksione paralelisht.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

Transaksionet e njëkohshme mund të shohin të dhënat e njëri-tjetrit. Pra, kemi nivelin më të thjeshtë, por edhe më të shpejtë të izolimit: LEXONI PA KOMITIM.

Në parim, kjo mund të pritet për globalët, për të cilët performanca ka qenë gjithmonë një përparësi kryesore.

Po sikur të na duhet një nivel më i lartë izolimi në operacionet globale?

Këtu duhet të mendojmë pse janë të nevojshme nivelet e izolimit dhe si funksionojnë ato.

Niveli më i lartë i izolimit, SERIALIZE, do të thotë që rezultati i transaksioneve të ekzekutuara paralelisht është ekuivalent me ekzekutimin e tyre sekuencial, gjë që garanton mungesën e përplasjeve.

Ne mund ta bëjmë këtë me ndihmën e kyçjeve kompetente në ObjectScript, të cilat kanë shumë mënyra të ndryshme aplikimi: ju mund të bëni kyçje të rregullta, graduale, të shumëfishta me komandën LOCK.

Nivelet më të ulëta të izolimit janë kompromise të dizajnuara për të përmirësuar performancën e bazës së të dhënave.

Le të shohim se si mund të arrijmë nivele të ndryshme izolimi duke përdorur brava.

Ky operator ju lejon të merrni jo vetëm bllokime ekskluzive të nevojshme për të ndryshuar të dhënat, por edhe të ashtuquajturat bllokime të përbashkëta, të cilat mund të merren paralelisht nga disa fije në të njëjtën kohë kur ato duhet të lexojnë të dhëna që nuk duhet të ndryshohen nga procese të tjera gjatë procesit të leximit.

Mësoni më shumë rreth metodës së bllokimit dyfazor në rusisht dhe anglisht:

→ Bllokim dyfazor
→ Mbyllje me dy faza

Vështirësia qëndron në faktin se gjatë një transaksioni, gjendja e bazës së të dhënave mund të jetë e paqëndrueshme, por këto të dhëna të paqëndrueshme janë të dukshme për proceset e tjera. Si mund të shmanget kjo?

Duke përdorur kyçe, do të krijojmë dritare dukshmërie brenda të cilave gjendja e bazës së të dhënave do të jetë konsistente. I gjithë aksesi në këto dritare dukshmërie të gjendjes konsistente do të kontrollohet nga kyçet.

Kyçjet e pĂ«rbashkĂ«ta nĂ« tĂ« njĂ«jtat tĂ« dhĂ«na janĂ« tĂ« ripĂ«rdorshme—ato mund tĂ« merren nga procese tĂ« shumĂ«fishta. KĂ«to kyçje parandalojnĂ« qĂ« proceset e tjera tĂ« modifikojnĂ« tĂ« dhĂ«nat, qĂ« do tĂ« thotĂ« se ato pĂ«rdoren pĂ«r tĂ« krijuar dritare me gjendje tĂ« qĂ«ndrueshme tĂ« bazĂ«s sĂ« tĂ« dhĂ«nave.

Kyçjet ekskluzive pĂ«rdoren pĂ«r tĂ« modifikuar tĂ« dhĂ«nat—vetĂ«m njĂ« proces mund tĂ« fitojĂ« njĂ« kyçje tĂ« tillĂ«. NjĂ« kyçje ekskluzive mund tĂ« fitohet nga:

  1. Çdo proces nĂ«se tĂ« dhĂ«nat janĂ« tĂ« lira
  2. Vetëm procesi që ka një kyç të përbashkët në këto të dhëna dhe ishte i pari që kërkoi një kyç ekskluziv.

Transaksionet në InterSystems IRIS globals

Sa më e ngushtë të jetë dritarja e dukshmërisë, aq më gjatë duhet të presin proceset e tjera për të, por aq më konsistente mund të jetë gjendja e bazës së të dhënave brenda saj.

LEXUAR_I_AMANDUAR — thelbi i kĂ«tij niveli Ă«shtĂ« se ne shohim vetĂ«m tĂ« dhĂ«na tĂ« kryera nga fije tĂ« tjera. NĂ«se tĂ« dhĂ«nat nĂ« njĂ« transaksion tjetĂ«r nuk janĂ« kryer ende, ne shohim versionin e tij tĂ« vjetĂ«r.

Kjo na lejon të paralelizojmë punën në vend që të presim që të lirohet kyçi.

Pa disa truke të veçanta, nuk do të jemi në gjendje të shohim versionin e vjetër të të dhënave në IRIS, kështu që do të na duhet të mjaftohemi me brava.

Prandaj, do të na duhet të përdorim kyçje të përbashkëta për të lejuar leximin e të dhënave vetëm në momente konsistence.

Le të themi se kemi një bazë përdoruesish ^persona që transferojnë para te njëri-tjetri.

Momenti i transferimit nga personi 123 tek personi 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)

Momenti i kërkesës së shumës së parave nga personi 123 para shlyerjes duhet të shoqërohet nga një bllokim ekskluziv (sipas parazgjedhjes):

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

Nëse keni nevojë të shfaqni bilancin e llogarisë suaj në llogarinë tuaj personale, mund të përdorni bllokimin e përbashkët ose të mos e përdorni fare:

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

Megjithatë, nëse supozojmë se operacionet në bazën e të dhënave kryhen pothuajse menjëherë (më lejoni t'ju kujtoj se globalet janë një strukturë e nivelit shumë më të ulët sesa një tabelë relacionale), atëherë nevoja për këtë nivel zvogëlohet.

LEXIM I PËRSËRITSHËM — Ky nivel izolimi lejon lexime tĂ« shumĂ«fishta tĂ« tĂ« dhĂ«nave qĂ« mund tĂ« modifikohen nga transaksionet e njĂ«kohshme.

Prandaj, do të na duhet të caktojmë një bllokim të përbashkët për leximin e të dhënave që po ndryshojmë dhe bllokime ekskluzive për të dhënat që po ndryshojmë.

Për fat të mirë, operatori LOCK ju lejon të listoni në detaje të gjitha bravat e nevojshme, të cilat mund të jenë shumë, në një operator.

LOCK +^person(123, amount)#”S”
Ń‡Ń‚Đ”ĐœĐžĐ” ^person(123, amount)

operacione të tjera (në këtë kohë, fijet paralele përpiqen të ndryshojnë ^person(123, amount), por nuk munden)

LOCK +^person(123, amount)
ĐžĐ·ĐŒĐ”ĐœĐ”ĐœĐžĐ” ^person(123, amount)
LOCK -^person(123, amount)

Ń‡Ń‚Đ”ĐœĐžĐ” ^person(123, amount)
LOCK -^person(123, amount)#”S”

Kur renditni bravat e ndara me presje, ato merren në mënyrë sekuenciale, dhe nëse e bëni këtë:

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

pastaj ato merren në mënyrë atomike të gjitha menjëherë.

SERIALIZO — Do tĂ« na duhet tĂ« konfigurojmĂ« bllokimet nĂ« mĂ«nyrĂ« qĂ« tĂ« gjitha transaksionet qĂ« ndajnĂ« tĂ« dhĂ«na tĂ« ekzekutohen pĂ«rfundimisht nĂ« mĂ«nyrĂ« sekuenciale. PĂ«r kĂ«tĂ« qasje, shumica e bllokimeve duhet tĂ« jenĂ« ekskluzive dhe tĂ« merren nĂ« rajonet mĂ« tĂ« vogla tĂ« globalit pĂ«r arsye performance.

Nëse flasim për shlyerje të fondeve në ^person global, atëherë vetëm niveli i izolimit SERIALIZE është i pranueshëm për të, pasi paratë duhet të shpenzohen në mënyrë strikte sekuenciale, përndryshe është e mundur të shpenzohet e njëjta shumë disa herë.

4. Qëndrueshmëria

Unë kryeva teste me prerje të fortë të enës me anë të

docker kill my-iris

Baza i toleroi mirë. Nuk u hasën probleme.

Përfundim

InterSystems IRIS mbështet transaksionet për globalet. Ato janë vërtet atomike dhe të besueshme. Sigurimi i konsistencës së bazës së të dhënave me globalet kërkon përpjekje nga programuesi dhe përdorimin e transaksioneve, pasi i mungojnë konstrukte komplekse të integruara si çelësat e huaj.

Niveli i izolimit për globalët pa përdorur kyçje është READ UNCOMMITTED, dhe me kyçje mund të arrihet deri në nivelin SERIALIZE.

Korrektësia dhe shpejtësia e transaksioneve në global-e varet shumë nga aftësia e programuesit: sa më gjerësisht të përdoren kyçet e përbashkëta për lexim, aq më i lartë është niveli i izolimit, dhe sa më shumë të përdoren kyçet ngushtësisht ekskluzive, aq më e lartë është performanca.

Burimi: www.habr.com

Shto një koment