Tranzakciók az InterSystems IRIS globals szolgáltatásban

Tranzakciók az InterSystems IRIS globals szolgáltatásbanAz InterSystems IRIS DBMS érdekes adattárolási struktúrákat támogat – globálisakat. Lényegében többszintű kulcsokról van szó, amelyek különféle kiegészítő szolgáltatásokat kínálnak tranzakciók formájában, gyors funkciók az adatfák bejárásához, zárak és saját ObjectScript nyelv.

A globalokról bővebben a „Globálok az adatok tárolására szolgáló kincses kardok” című cikksorozatban olvashat:

fák. 1. rész
fák. 2. rész
Ritka tömbök. 3. rész

Érdekelt, hogy a tranzakciók hogyan valósulnak meg a globalokban, milyen funkciók vannak. Hiszen ez egy teljesen más struktúra az adatok tárolására, mint a szokásos táblák. Sokkal alacsonyabb szinten.

Amint az a relációs adatbázisok elméletéből ismeretes, a tranzakciók jó megvalósításának meg kell felelnie a követelményeknek SAV:

A - Atom (atomosság). A tranzakcióban végrehajtott minden változás, vagy az egyik sem kerül rögzítésre.

C - Következetesség. A tranzakció befejezése után az adatbázis logikai állapotának belsőleg konzisztensnek kell lennie. Ez a követelmény sok szempontból a programozót érinti, de az SQL adatbázisok esetében az idegen kulcsokat is.

Én - Elszigetelek. A párhuzamosan futó tranzakciók nem érinthetik egymást.

D - Tartós. Egy tranzakció sikeres befejezése után az alacsonyabb szintű problémák (például áramszünet) nem befolyásolhatják a tranzakció által módosított adatokat.

A globálisok nem relációs adatstruktúrák. Úgy tervezték, hogy nagyon korlátozott hardveren szupergyorsan működjenek. Nézzük meg a tranzakciók megvalósítását a globals segítségével hivatalos IRIS docker kép.

Az IRIS-ben történő tranzakciók támogatásához a következő parancsok használatosak: TSTART, TCOMMIT, TROLLBACK.

1. Atomosság

A legegyszerűbb módja az atomitás ellenőrzésének. Az adatbázis-konzolról ellenőrizzük.

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

Aztán arra következtetünk:

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

Kapunk:

1 2 3

Minden rendben. Az atomitás megmarad: minden változás rögzítésre kerül.

Bonyolítsuk le a feladatot, vessünk be egy hibát, és nézzük meg, hogyan menti el a tranzakciót, részben vagy egyáltalán nem.

Ellenőrizzük még egyszer az atomitást:

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

Ezután erőszakkal leállítjuk a konténert, elindítjuk és meglátjuk.

docker kill my-iris

Ez a parancs szinte egyenértékű a kényszerleállítással, mivel SIGKILL jelet küld a folyamat azonnali leállítására.

Lehet, hogy a tranzakciót részben elmentették?

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

- Nem, nem élte túl.

Próbáljuk meg a rollback parancsot:

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)

Semmi sem maradt fenn.

2. Következetesség

Mivel a globalokra épülő adatbázisokban a kulcsok is globalokon készülnek (hadd emlékeztessem Önöket arra, hogy a global egy alacsonyabb szintű adattárolási struktúra, mint a relációs tábla), a konzisztencia követelmény teljesítése érdekében kulcsmódosítást kell beépíteni. ugyanabban a tranzakcióban, mint a globális változás.

Például van egy globális ^személyünk, amelyben személyiségeket tárolunk, és kulcsként a TIN-t használjuk.

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

A vezeték- és keresztnév szerinti gyors keresés érdekében elkészítettük az ^index billentyűt.

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

Annak érdekében, hogy az adatbázis konzisztens legyen, a következőképpen kell hozzáadnunk a személyt:

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

Ennek megfelelően a törléskor egy tranzakciót is használnunk kell:

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

Más szóval, a konzisztencia követelményének teljesítése teljes mértékben a programozó vállán nyugszik. De ami a globálisokat illeti, ez normális, alacsony szintű természetük miatt.

3. Elszigetelődés

Itt kezdődnek a vadonok. Sok felhasználó dolgozik egyszerre ugyanazon az adatbázison, és ugyanazokat az adatokat változtatja meg.

A helyzet ahhoz hasonlítható, amikor sok felhasználó egyidejűleg dolgozik ugyanazzal a kódtárral, és egyszerre több fájl módosítását próbálja végrehajtani.

Az adatbázisnak mindent valós időben kell rendeznie. Tekintettel arra, hogy a komoly cégeknél még egy külön személy is felelős a verziókezelésért (ágak összevonása, konfliktusok megoldása stb.), és mindezt az adatbázisnak valós időben kell megtennie, a feladat összetettsége és a program helyessége. adatbázis tervezés és az azt kiszolgáló kód.

Az adatbázis nem tudja megérteni a felhasználók által végrehajtott műveletek jelentését az ütközések elkerülése érdekében, ha ugyanazon az adatokon dolgoznak. Csak egy olyan tranzakciót tud visszavonni, amely ütközik egy másikkal, vagy végrehajthatja azokat egymás után.

További probléma, hogy egy tranzakció végrehajtása során (commit előtt) az adatbázis állapota inkonzisztens lehet, ezért kívánatos, hogy más tranzakciók ne férhessenek hozzá az adatbázis inkonzisztens állapotához, ami a relációs adatbázisokban érhető el. sokféleképpen: pillanatképek, több verziójú sorok létrehozása stb.

A tranzakciók párhuzamos lebonyolításánál fontos számunkra, hogy azok ne zavarják egymást. Ez az elszigeteltség tulajdonsága.

Az SQL 4 elkülönítési szintet határoz meg:

  • OLVASSA EL KÖTELEZETLEN
  • ELKÖTÖTT ELOLVASÁS
  • ISMÉTELHETŐ OLVASÁS
  • SOROZHATÓ

Nézzük meg az egyes szinteket külön-külön. Az egyes szintek megvalósításának költségei szinte exponenciálisan nőnek.

OLVASSA EL KÖTELEZETLEN - ez az elszigeteltség legalacsonyabb szintje, ugyanakkor a leggyorsabb. A tranzakciók képesek olvasni az egymás által végrehajtott módosításokat.

ELKÖTÖTT ELOLVASÁS az elszigetelés következő szintje, ami kompromisszum. A tranzakciók nem tudják elolvasni egymás módosításait a commit előtt, de elolvashatják a véglegesítés utáni módosításokat.

Ha van egy hosszú T1 tranzakciónk, amely során a T2, T3 ... Tn tranzakciókban commit történt, ami ugyanazokkal az adatokkal működött, mint a T1, akkor a T1-ben történő adatkérésnél minden alkalommal más eredményt kapunk. Ezt a jelenséget nem megismételhető olvasásnak nevezzük.

ISMÉTELHETŐ OLVASÁS - ezen az elkülönítési szinten nem fordul elő a nem megismételhető olvasás jelensége, mivel minden adatolvasási kérésnél pillanatfelvétel készül az eredményadatokról, és amikor újra felhasználjuk ugyanabban a tranzakcióban, akkor a pillanatképből származó adatok használt. Ezen az elkülönítési szinten azonban lehetőség van fantomadatok olvasására. Ez a párhuzamos végrehajtott tranzakciók által hozzáadott új sorok beolvasására vonatkozik.

SOROZHATÓ – a legmagasabb szintű szigetelés. Jellemzője, hogy a tranzakció során bármilyen módon felhasznált adatok (olvasás vagy változás) csak az első tranzakció lebonyolítása után válnak más tranzakciók rendelkezésére.

Először is nézzük meg, hogy a műveletek elkülönítve vannak-e a fő száltól. Nyissunk meg 2 terminál ablakot.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Nincs elszigeteltség. Az egyik szál azt látja, hogy mit csinál a második, aki megnyitotta a tranzakciót.

Nézzük meg, hogy a különböző szálak tranzakciói látják-e, mi történik bennük.

Nyissunk meg 2 terminál ablakot és nyissunk meg 2 tranzakciót párhuzamosan.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

A párhuzamos tranzakciók egymás adatait látják. Tehát megkaptuk a legegyszerűbb, de egyben a leggyorsabb izolációs szintet is, a READ UNCOMMITED.

Ez elvileg elvárható lenne a globaloknál, akiknél mindig is a teljesítmény volt az elsődleges.

Mi van akkor, ha magasabb szintű elszigeteltségre van szükségünk a globális műveleteknél?

Itt el kell gondolkodni azon, hogy egyáltalán miért van szükség az izolációs szintekre, és hogyan működnek.

A legmagasabb elkülönítési szint, a SERIALIZE azt jelenti, hogy a párhuzamosan végrehajtott tranzakciók eredménye egyenértékű a szekvenciális végrehajtásukkal, ami garantálja az ütközések elkerülését.

Ezt az ObjectScript intelligens záraival tehetjük meg, amelyeknek nagyon sokféle felhasználása van: a paranccsal normál, növekményes, többszörös zárolást végezhetünk. LOCK.

Az alacsonyabb elkülönítési szintek kompromisszumok az adatbázis sebességének növelésére.

Nézzük meg, hogyan érhetünk el különböző szintű szigetelést zárak segítségével.

Ezzel az operátorral nem csak az adatok megváltoztatásához szükséges exkluzív zárolásokat veheti igénybe, hanem úgynevezett megosztott zárakat is, amelyek több szálon is párhuzamosan vehetnek részt, amikor olyan adatokat kell beolvasniuk, amelyeket más folyamatoknak nem szabad megváltoztatniuk az olvasási folyamat során.

További információ a kétfázisú blokkolási módszerről orosz és angol nyelven:

Kétfázisú blokkolás
Kétfázisú zár

A nehézség az, hogy egy tranzakció során az adatbázis állapota inkonzisztens lehet, de ez az inkonzisztens adat látható más folyamatok számára. Hogyan lehet ezt elkerülni?

A zárak segítségével láthatósági ablakokat hozunk létre, amelyekben az adatbázis állapota konzisztens lesz. A megállapodás szerinti állapot ilyen ablakaihoz való hozzáférést pedig zárak fogják szabályozni.

Az ugyanazon adatokon lévő megosztott zárolások újrafelhasználhatók – több folyamat is igénybe veheti őket. Ezek a zárak megakadályozzák, hogy más folyamatok megváltoztassák az adatokat, pl. konzisztens adatbázisállapotú ablakok kialakítására szolgálnak.

Exkluzív zárolásokat használnak az adatmódosításokhoz – csak egy folyamat képes ilyen zárolásra. Exkluzív zárat a következők vehetnek igénybe:

  1. Bármilyen folyamat, ha az adatok ingyenesek
  2. Csak az a folyamat, amelynek megosztott zárolása van ezen adatokon, és elsőként kért kizárólagos zárolást.

Tranzakciók az InterSystems IRIS globals szolgáltatásban

Minél szűkebb a láthatósági ablak, annál tovább kell rá várnia a többi folyamatnak, de annál konzisztensebb lehet a benne lévő adatbázis állapota.

READ_COMMITTED — ennek a szintnek az a lényege, hogy más szálakból csak lekötött adatokat látunk. Ha egy másik tranzakció adata még nincs véglegesítve, akkor a régi verzióját látjuk.

Ez lehetővé teszi a munka párhuzamosítását, ahelyett, hogy a zár feloldására várnánk.

Különleges trükkök nélkül nem láthatjuk majd az IRIS-ben az adatok régi verzióját, így be kell érnünk a zárakkal.

Ennek megfelelően megosztott zárakat kell használnunk, hogy az adatok csak a konzisztencia pillanataiban olvashatók le.

Tegyük fel, hogy van egy felhasználói bázisunk, aki pénzt utal át egymásnak.

A 123-as személyről a 242-es személyre történő áthelyezés pillanata:

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)

A 123-as személytől a terhelés előtti pénzösszeg igénylésének pillanatát egy kizárólagos blokkolásnak kell kísérnie (alapértelmezés szerint):

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

És ha meg kell mutatnia a fiók állapotát a személyes fiókjában, akkor használhat megosztott zárat, vagy egyáltalán nem használja:

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

Ha azonban feltételezzük, hogy az adatbázis-műveletek szinte azonnal végrehajtódnak (hadd emlékeztessem önöket arra, hogy a globalok sokkal alacsonyabb szintű struktúrák, mint a relációs táblák), akkor csökken az igény erre a szintre.

ISMÉTELHETŐ OLVASÁS - Ez az elkülönítési szint lehetővé teszi az adatok többszöri leolvasását, amelyeket egyidejű tranzakciók módosíthatnak.

Ennek megfelelően megosztott zárolást kell alkalmaznunk a megváltoztatott adatok olvasásához, és kizárólagos zárolást a megváltoztatott adatokhoz.

Szerencsére a LOCK operátor lehetővé teszi, hogy egy nyilatkozatban részletesen felsoroljuk az összes szükséges zárat, amelyekből sok lehet.

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

egyéb műveletek (jelenleg a párhuzamos szálak megpróbálják megváltoztatni a ^személyt(123, összeg), de nem)

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

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

A vesszővel elválasztott zárak listázása során a rendszer sorban veszi őket, de ha ezt teszi:

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

akkor egyszerre atomosan veszik őket.

SZERIALIZÁLJ — zárolást kell beállítanunk, hogy végül minden közös adattal rendelkező tranzakció egymás után kerüljön végrehajtásra. Ehhez a megközelítéshez a legtöbb zárnak kizárólagosnak kell lennie, és a teljesítmény érdekében a globális legkisebb területein kell lennie.

Ha a globális ^személyben történő pénzterhelésről beszélünk, akkor csak a SERIALIZE izolációs szint fogadható el, mivel a pénzt szigorúan szekvenciálisan kell elkölteni, különben ugyanazt az összeget többször is el lehet költeni.

4. Tartósság

A teszteket a tartály kemény vágásával végeztem

docker kill my-iris

A bázis jól tűrte őket. Problémát nem azonosítottak.

Következtetés

A globális felhasználók számára az InterSystems IRIS rendelkezik tranzakciós támogatással. Valóban atomosak és megbízhatóak. A globalokon alapuló adatbázis konzisztenciájának biztosításához programozói erőfeszítésekre és tranzakciók használatára van szükség, mivel nem tartalmaz bonyolult beépített konstrukciókat, például idegen kulcsokat.

A zárak használata nélküli globalok izolációs szintje READ UNCOMMITED, zárak használatakor pedig a SERIALIZE szintig biztosítható.

A tranzakciók helyessége és gyorsasága a globalokon nagymértékben függ a programozó készségétől: minél szélesebb körben megosztott zárakat használunk az olvasás során, annál magasabb az izoláció szintje, és minél szűkebb körben kizárólagos zárakat veszünk, annál gyorsabb a teljesítmény.

Forrás: will.com

Hozzászólás