Transaksionet në globalet InterSystems IRIS

Transaksionet nĂ« globalet InterSystems IRISDB InterSystems IRIS mbĂ«shtet struktura interesante pĂ«r ruajtjen e tĂ« dhĂ«nave — globalet. NĂ« thelb, kĂ«to janĂ« çelĂ«sa shumĂ«-nivele me disa pĂ«rfitime tĂ« tjera si transaksionet, funksione tĂ« shpejta pĂ«r kalimin pĂ«rmes pemĂ«ve tĂ« tĂ« dhĂ«nave, bllokimet dhe gjuha e vet ObjectScript.

MĂ« shumĂ« rreth globalĂ«ve nĂ« ciklin e artikujve «Globalet — shpata-kahena pĂ«r ruajtjen e tĂ« dhĂ«nave»:

Pemët. Pjesa 1
Pemët. Pjesa 2
Matrica të thinjura. Pjesa 3

Më ka interesuar se si janë realizuar transaksionet në globalet, çfarë veçorish janë aty. Sepse kjo është një strukturë krejtësisht tjetër për ruajtjen e të dhënave, ndryshe nga tabelat e njohura. Shumë më e nivelit të ulët.

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

A — Atomic (atomik). TĂ« gjitha ndryshimet e bĂ«ra nĂ« transaksion duhet tĂ« regjistrohen ose asnjĂ« prej tyre.

C — Consistency (koherencĂ«). Pas pĂ«rfundimit tĂ« transaksionit, gjendja logjike e DB-sĂ« duhet tĂ« jetĂ« e brendshme dhe e qĂ«ndrueshme. NĂ« masĂ« tĂ« madhe, kjo kĂ«rkesĂ« u takon programuesve, por nĂ« rastin e databazave SQL, ajo gjithashtu ka tĂ« bĂ«jĂ« me çelĂ«sat e jashtĂ«m.

I — Isolate (izolim). Transaksionet qĂ« ekzekutohen paralelisht nuk duhet tĂ« ndikojnĂ« njĂ«ra-tjetrĂ«n.

D — Durable (qĂ«ndrueshmĂ«ri). Pas pĂ«rfundimit tĂ« suksesshĂ«m tĂ« transaksionit, problemet nĂ« nivelet e poshtme (siç Ă«shtĂ« njĂ« prishje e energjisĂ«) nuk duhet tĂ« ndikojnĂ« nĂ« tĂ« dhĂ«nat e ndryshuara nga transaksioni.

Globalet janë struktura të dhënash jo relacionale. Ato janë krijuar për të punuar shumë shpejt në harduer shumë të kufizuar. Le të shqyrtojmë realizimin e transaksioneve në globalet me ndihmën e imazhit zyrtar docker të IRIS.

Për të mbështetur transaksionet në IRIS përdoren komandat: TSTART, TCOMMIT, TROLLBACK.

1. Atomikësia

Më lehtë është të verifikohet atomikësia. Verifikohet nga konsola e databazës.

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

Pastaj arrijmë në përfundimin:

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

Do të marrim:

1 2 3

E gjithë gjendja është në rregull. Atomikësia është ruajtur: të gjitha ndryshimet janë regjistruar.

Le të komplikojmë gjënë, të fusim një gabim dhe të shohim si do të ruajë transaksioni, pjesërisht ose aspak.

Tjetër herë do të kontrollojmë atomikësinë:

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

Pas kësaj do të ndalojmë me forcë kontejnerin, do ta aktivizojmë dhe do të shohim.

docker kill my-iris

Kjo komandë është praktikisht ekuivalente me ndalimin e detyrueshëm të energjisë, pasi dërgon sinjalin e ndalimit të menjëhershëm të procesit SIGKILL.

A mund të ketë ruajtur transaksioni pjesërisht?

SHKRUAJ ^a(1), ^a(2), ^a(3)
^
 ^a(1)

— Jo, nuk u ruajt.

Të provojmë komandën e rikthimit:

Vrit ^A
TSTART
Cakto ^a(1) = 1
Cakto ^a(2) = 2
Cakto ^a(3) = 3
TROLLBACK

SHKRUAJ ^a(1), ^a(2), ^a(3)
^
 ^a(1)

Asgjë nuk u ruajt gjithashtu.

2. Koherenca

Duke pasur parasysh që në bazat mbi globale, çelësat bëhen gjithashtu mbi globale (kujdesi që globali është një strukturë më e ulët për ruajtjen e të dhënave se tabela relacional), për të përmbushur kërkesën e koherencës duhet të përfshihet ndryshimi i çelësit në të njëjtën transaksion me ndryshimin e globalit.

Për shembull, ne kemi globalin ^person, ku ruajmë persona dhe si çelës përdorim INN.

^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 kemi krijuar çelësin ^index.

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

Për të pasur një bazë koherente, duhet të shtojmë personin kështu:

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

Për pasojë, kur fshijmë gjithashtu duhet të përdorim transaksionin:

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

Me fjalĂ« tĂ« tjera, pĂ«rmbushja e kĂ«rkesĂ«s sĂ« koherencĂ«s Ă«shtĂ« plotĂ«sisht mbi supet e programuesit. Por kur flitet pĂ«r globale — kjo Ă«shtĂ« e natyrshme, pĂ«r shkak tĂ« natyrĂ«s sĂ« tyre tĂ« ulĂ«t.

3. Izolimi

Këtu fillojnë ndërlikimet. Shumë përdorues punojnë njëkohësisht mbi të njëjtën bazë, ndryshojnë të dhëna të njëjta.

Situata është e krahasueshme me atë kur shumë përdorues punojnë njëkohësisht me të njëjtin repo të kodit dhe përpiqen gjithashtu të bëjnë commit të ndryshimeve në shumë skedarë njëkohësisht.

Baza e të dhënave duhet ta zgjidhë këtë në kohë reale. Duke marrë parasysh që në kompani serioze ka madje një person të veçantë që është përgjegjës për kontrollin e versioneve (për bashkimin e degëve, zgjidhjen e konflikteve, etj.), dhe DB duhet t'i bëjë të gjitha këto në kohë reale, atëherë bëhet e qartë kompleksiteti i detyrës dhe saktësia e projektimit të bazës së të dhënave dhe kodit që e mbështet atë.

Baza e të dhënave nuk mund të kuptojë kuptimin e veprimeve që kryejnë përdoruesit, për të parandaluar konflikte, nëse ata punojnë me të njëjtat të dhëna. Ajo mund të anulojë vetëm një transaksion që është në kundërshtim me një tjetër ose t'i ekzekutojë ato në mënyrë sekondare.

Një tjetër problem është se gjatë ekzekutimit të një transaksioni (para angazhimit), gjendja e bazës mund të jetë e paqëndrueshme, prandaj është e preferueshme që transaksionet e tjera të mos kenë akses në gjendjen e paqëndrueshme të bazës së të dhënave, çka realizohet në DB rrelacionale përmes shumë mënyrave: krijimin e snapshot-eve, shumëversionalitetit të rreshtave dhe të tjerë.

Gjatë ekzekutimit paralel të transaksioneve, është e rëndësishme që ato të mos pengojnë njëra-tjetrën. Kjo është ajo që njihet si pronësia e izollimit.

SQL përcakton 4 nivele izollimi:

  • LEXO TË PAANGAZHUARA
  • LEXO TË ANGAZHUARA
  • LEXO RIPORTUESHME
  • SERIALIZABLE

Të shqyrtojmë çdo nivel veçmas. Kostot për implementimin e çdo niveli rriten pothuajse eksponencialisht.

LEXO TË PAANGAZHUARA — ky Ă«shtĂ« niveli mĂ« i ulĂ«t i izollimit, por nĂ« tĂ« njĂ«jtĂ«n kohĂ« mĂ« i shpejti. Transaksionet mund tĂ« lexojnĂ« ndĂ«rrimet e bĂ«rĂ« nga njĂ«ra-tjetrĂ«n.

LEXO TË ANGAZHUARA — ky Ă«shtĂ« niveli tjetĂ«r i izollimit, i cili Ă«shtĂ« njĂ« kompromis. Transaksionet nuk mund tĂ« lexojnĂ« ndryshimet e bĂ«ra nga njĂ«ra-tjetrĂ«n deri nĂ« angazhim, por mund tĂ« lexojnĂ« çdo ndryshim tĂ« bĂ«rĂ« pas angazhimit.

Nëse kemi një transaksion të gjatë T1, gjatë të cilit ka pasur angazhime në transaksionet T2, T3 ... Tn, të cilat punonin me të njëjtat të dhëna si T1, atëherë gjatë kërkesës për të dhëna në T1 do të marrim çdo herë një rezultat të ndryshëm. Ky fenomen njihet si leximi i pakthyeshëm.

LEXO RIPORTUESHME — nĂ« kĂ«tĂ« nivel izollimi nuk kemi fenomenin e leximit tĂ« pakthyeshĂ«m, pĂ«r shkak se pĂ«r çdo kĂ«rkesĂ« pĂ«r tĂ« lexuar tĂ« dhĂ«na krijohet njĂ« snapshot i tĂ« dhĂ«nave si rezultat dhe kur pĂ«rdoret pĂ«rsĂ«ri nĂ« kĂ«tĂ« transaksion, pĂ«rdoren tĂ« dhĂ«nat nga snapshot-i. MegjithatĂ«, nĂ« kĂ«tĂ« nivel izollimi Ă«shtĂ« e mundur tĂ« lexohen tĂ« dhĂ«na fantazmĂ«. KĂ«tu do tĂ« thotĂ« tĂ« lexohen rreshta tĂ« rinj qĂ« janĂ« shtuar nga transaksionet paralel tĂ« angazhuara.

SERIALIZABLE — niveli mĂ« i lartĂ« i izollimit. Ai karakterizohet nga fakti se tĂ« dhĂ«nat qĂ« pĂ«rdoren nĂ« ndonjĂ« mĂ«nyrĂ« nĂ« transaksion (leximi ose ndryshimi) bĂ«hen tĂ« aksesueshme pĂ«r transaksione tĂ« tjera vetĂ«m pas pĂ«rfundimit tĂ« transaksionit tĂ« parĂ«.

Fillimi, le të kuptojmë nëse ka izolim të operacioneve në transaksion nga rrjedha kryesore. Do të hapim 2 dritare terminali.

Vrit ^t

Shkruaj ^t(1)
2

TSTART
Vendos ^t(1)=2

Nuk ka izolim. Një rrjedhë sheh se çfarë bën tjetra që ka hapur transaksionin.

Le të shohim nëse transaksionet e rrjedhave të ndryshme shohin atë që ndodh brenda tyre.

Do të hapim 2 dritare terminali dhe do të hapim 2 transaksione paralelisht.

vrit ^t
TSTART
Shkruaj ^t(1)
3

TSTART
Vendos ^t(1)=3

Transaksionet paralelisht shohin të dhënat e njëra-tjetrës. Pra, kemi marrë nivelin më të thjeshtë, por edhe më të shpejtë të izolimit READ UNCOMMITED.

Në parim, kjo mund të pritej për globalët, për të cilët performanca gjithmonë është vendosur në krye të listës.

ÇfarĂ« tĂ« bĂ«jmĂ« nĂ«se na nevojitet njĂ« nivel mĂ« i lartĂ« izolimi nĂ« operacionet mbi globalĂ«t?

Këtu duhet të mendojmë përse na nevojiten nivelet e izolimit dhe si funksionojnë ato.

Niveli më i lartë i izolimit SERIALIZE do të thotë se rezultati i transaksioneve që ekzekutohen paralelisht është ekuivalent me ekzekutimin e tyre të radhitur, që garanton mungesën e kolizionëve.

Këtë mund ta bëjmë me ndihmën e bllokimeve të mençura në ObjectScript, të cilat kanë një numër të madh përdorimesh: mund të krijojmë bllokim standard, inkremental, shumëfish me komandën LOCK.

Niveli më të ulëta të izolimit janë kompromise që synojnë të rrisin shpejtësinë e funksionimit të bazës së të dhënave.

Le të shohim si mund të arrijmë nivele të ndryshme izolimi me ndihmën e bllokimeve.

Ky operacion lejon të merret jo vetëm bllokimi ekskluziv, i nevojshëm për ndryshimin e të dhënave, por gjithashtu të ashtuquajturat shared, të cilat mund të merret paralelisht nga disa rrjedha, kur ata duhet të lexojnë të dhëna që nuk duhet të ndryshohen nga procese të tjera gjatë leximit.

Më shumë mbi metodën e dy fazave të bllokimeve në gjuhën ruse dhe angleze:

→ Bllokimi me dy faza
→ Two-phase locking

Vështirësia qëndron në faktin se gjatë transaksionit, gjendja e bazës mund të jetë jo konsistente, megjithatë këto të dhëna jo konsistente janë të dukshme për proceset e tjera. Si të evitoni këtë?

Ne do ta bëjmë me ndihmën e bllokimeve të tilla dritare të dukshmërisë, në të cilat gjendja e bazës do të jetë konsistente. Dhe të gjitha kërkesat për këto dritare të dukshmërisë me gjendje të konsistent do të kontrollohen nga bllokimet.

Bllokimet e ndara për të njëjtat të dhëna janë shumëfish, - mund t'i marrë disa procese. Këto bllokime ndalojnë procese të tjera të modifikojnë të dhënat, dmth ato përdoren për formimin e dritareve të një gjendjeje të konsoliduar të DB.

Bllokimet ekskluzive përdoren për modifikimin e të dhënave - një bllokim të tillë mund ta marrë vetëm një proces. Një bllokim ekskluziv mund të merret nga:

  1. Çdo proces, nĂ«se tĂ« dhĂ«nat janĂ« tĂ« lira
  2. Vetëm ai proces që ka një bllokim shared mbi këto të dhëna dhe që ka kërkuar i pari një bllokim ekskluziv.

Transaksionet në globalet InterSystems IRIS

Sa më e ngushtë të jetë dritarja e dukshmërisë, aq më gjatë duhet të presin proceset e tjera, por aq më konsistente mund të jetë gjendja e DB-së brenda saj.

READ_COMMITED - thelbi i këtij niveli është që ne shohim vetëm të dhënat e komituara nga rrjedhat e tjera. Nëse të dhënat në një transaksion tjetër nuk janë ende të komituara, ne i shohim versionin e tyre të vjetër.

Kjo na lejon të realizojmë punën paralelisht në vend që të presim lirimin e bllokimit.

Pa përpjekje të veçanta ne nuk do të mund të shohim versionin e vjetër të të dhënave në IRIS, kështu që do të duhet të pregatisim bllokime.

Për pasojë, do të duhet të lejojmë leximin e të dhënave vetëm në momentet e konsolidimit duke përdorur bllokime shared.

Supozoni se kemi një bazë përdoruesish ^person, që transferojnë para njëri-tjetrit.

Momenti i transferimit nga persona 123 te persona 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 për shumën e parave te persona 123 para shkarkimit duhet të shoqërohet nga një bllokim ekskluziv (sipërfaqësisht):

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

E nëse duam të tregojmë gjendjen e llogarisë në panelin personal, atëherë mund të përdorim një bllokim shared ose madje ta lëmë pa të:

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

Megjithatë, nëse supozojmë se operacionet me DB-në kryhen praktikisht menjëherë (të kujtojmë, që globalët janë një strukturë shumë më e ulët se tabela relacionale), atëherë nevoja për këtë nivel bie.

LEXO RIPORTUESHME - në këtë nivel izolimi lejohet që mund të jenë disa lexime të dhënash që mund të ndryshohen nga transaksione paralele.

Për pasojë, do të duhet të vendosim një bllokim shared për të lexuar të dhënat që ne i ndryshojmë dhe bllokime ekskluzive për të dhënat që po modifikojmë.

Operatori LOCK lejon që në një operator të vetëm të enumerosh në mënyrë të detajuar të gjitha bllokimet e nevojshme, të cilat mund të jenë shumë.

LOCK +^person(123, amount)#”S”
leximi ^person(123, amount)

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

LOCK +^person(123, amount)
ndryshimi ^person(123, amount)
LOCK -^person(123, amount)

leximi ^person(123, amount)
LOCK -^person(123, amount)#”S”

Kur enumerate bllokimet me një presje, ato merren njëra pas tjetrës, ndërsa nëse e bëni kështu:

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

atëherë ato merren të gjitha në një mënyrë atomike.

SERIALIZE — ne do tĂ« duhet tĂ« vendosim bllokime nĂ« mĂ«nyrĂ« qĂ« nĂ« fund tĂ« gjitha transaksionet qĂ« kanĂ« tĂ« dhĂ«na tĂ« pĂ«rbashkĂ«ta tĂ« kryhen njĂ«ri pas tjetrit. PĂ«r kĂ«tĂ« qasje, shumica e bllokimeve duhet tĂ« jenĂ« ekskluzive dhe tĂ« merren nĂ« zonat mĂ« tĂ« vogla globale pĂ«r performancĂ«.

Nëse flasim për tërheqjen e fondeve në globalin ^person, për të është e pranueshme vetëm niveli i izolimit SERIALIZE, pasi paratë duhet të harxhohen rigorozisht një pas tjetrës, përndryshe është e mundur të harxhohet e njëjta shumë disa herë.

4. Qëndrueshmëria

Kam kryer testime me fikjen e ashpër të kontejnerit përmes

docker kill my-iris

Baza e tyre e mbante mirë. Nuk u zbulua ndonjë problem.

Përfundim

Për globalet në InterSystems IRIS ka mbështetje për transaksionet. Ato janë vërtet atomike, të besueshme. Për të siguruar qëndrueshmërinë e DB në globalet, kërkohen përpjekje nga programuesi dhe përdorimi i transaksioneve, pasi në të nuk ka struktura të ndërlikuara të ndërtuara siç janë çelësat e jashtëm.

Niveli i izolimit nĂ« globalet pa pĂ«rdorimin e bllokimeve — Ă«shtĂ« READ UNCOMMITTED, dhe me pĂ«rdorimin e bllokimeve mund tĂ« sigurohet deri nĂ« nivelin SERIALIZE.

Saktësia dhe shpejtësia e funksionimit të transaksioneve në globalet varen shumë nga mjeshtëria e programuesit: sa më gjerësisht të përdoren bllokimet ndarëse gjatë leximit, aq më i lartë është niveli i izolimit, dhe sa më ngushtësisht të merren bllokimet ekskluzive, aq më shumë performancë.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster