Трансакции во InterSystems IRIS globals

Трансакции во InterSystems IRIS globalsInterSystems IRIS DBMS поддржува интересни структури за складирање податоци - глобални. Во суштина, ова се клучеви на повеќе нивоа со разни дополнителни добрини во форма на трансакции, брзи функции за преминување стебла на податоци, брави и сопствен јазик ObjectScript.

Прочитајте повеќе за глобалните во серијата написи „Глобалите се мечеви со богатство за складирање податоци“:

Дрвја. Дел 1
Дрвја. Дел 2
Ретки низи. Дел 3

Се заинтересирав за тоа како се спроведуваат трансакциите во глобалните, какви карактеристики има. На крајот на краиштата, ова е сосема поинаква структура за складирање податоци од вообичаените табели. Многу пониско ниво.

Како што е познато од теоријата на релациони бази на податоци, добрата имплементација на трансакциите мора да ги задоволува барањата Киселина:

А - Атомска (атомска). Сите промени направени во трансакцијата или воопшто не се евидентирани.

В - Конзистентност. По завршувањето на трансакцијата, логичката состојба на базата на податоци мора да биде внатрешно конзистентна. На многу начини ова барање се однесува на програмерот, но во случајот на базите на податоци на SQL, исто така, се однесува на странски клучеви.

Јас - Изолирајте. Трансакциите кои се одвиваат паралелно не треба да влијаат едни на други.

Д - Издржлив. По успешното завршување на трансакцијата, проблемите на пониските нивоа (на пример, прекин на напојувањето) не треба да влијаат на податоците променети од трансакцијата.

Глобалите се нерелациски структури на податоци. Тие беа дизајнирани да работат супер брзо на многу ограничен хардвер. Ајде да погледнеме во спроведувањето на трансакции во глобалните со користење официјална слика на IRIS докер.

За поддршка на трансакции во IRIS, се користат следните команди: ТСТАРТ, TCOMMIT, ПРОЛАТУВАЊЕ.

1. Атомичност

Најлесен начин за проверка е атомичноста. Проверуваме од конзолата на базата на податоци.

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

Потоа заклучуваме:

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

Добиваме:

1 2 3

Се е во ред. Атомичноста се одржува: сите промени се евидентираат.

Ајде да ја комплицираме задачата, да воведеме грешка и да видиме како е зачувана трансакцијата, делумно или воопшто.

Ајде повторно да ја провериме атомичноста:

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

Потоа насилно ќе го запреме контејнерот, ќе го лансираме и ќе видиме.

docker kill my-iris

Оваа команда е речиси еквивалентна на принудно исклучување, бидејќи испраќа сигнал SIGKILL за веднаш да го запре процесот.

Можеби трансакцијата е делумно зачувана?

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

- Не, не преживеа.

Ајде да ја пробаме командата за враќање назад:

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)

Ништо не преживеало.

2. Конзистентност

Бидејќи во базите на податоци базирани на глобални, клучевите се прават и на глобалните (да ве потсетам дека глобалната е структура на пониско ниво за складирање податоци отколку релациска табела), за да се исполни условот за конзистентност, мора да се вклучи промена во клучот во истата трансакција како и промена на глобалната.

На пример, имаме глобално ^лице, во кое складираме личности и го користиме TIN-от како клуч.

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

За да имаме брзо пребарување по презиме и име, го направивме копчето ^index.

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

За да може базата на податоци да биде конзистентна, мора да ја додадеме личноста вака:

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

Според тоа, при бришење мора да користиме и трансакција:

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

Со други зборови, исполнувањето на условот за конзистентност целосно почива на рамениците на програмерот. Но, кога станува збор за глобалните, тоа е нормално, поради нивната природа на ниско ниво.

3. Изолација

Тука започнуваат дивините. Многу корисници истовремено работат на иста база на податоци, менувајќи ги истите податоци.

Ситуацијата е споредлива со кога многу корисници истовремено работат со исто складиште на код и се обидуваат истовремено да извршат промени на многу датотеки одеднаш.

Базата на податоци треба да го среди сето тоа во реално време. Имајќи предвид дека во сериозните компании постои дури и специјално лице кое е одговорно за контрола на верзијата (за спојување гранки, решавање конфликти итн.), а базата мора да го прави сето тоа во реално време, сложеноста на задачата и исправноста на дизајн на базата на податоци и код што му служи.

Базата на податоци не може да го разбере значењето на дејствијата што ги вршат корисниците со цел да се избегнат конфликти доколку работат на истите податоци. Може да поништи само една трансакција што е во конфликт со друга, или да ги изврши последователно.

Друг проблем е што при извршување на трансакција (пред извршување), состојбата на базата на податоци може да биде неконзистентна, па пожелно е другите трансакции да немаат пристап до неконзистентната состојба на базата, што се постигнува во релациони бази на податоци. на многу начини: создавање снимки, редови со повеќе верзии и сл.

При паралелно извршување на трансакциите, важно ни е тие да не се мешаат едни со други. Ова е својство на изолација.

SQL дефинира 4 нивоа на изолација:

  • ПРОЧИТАЈ НЕОБВРШЕНИ
  • ПРОЧИТАЈ ПОВРЗЕНИ
  • ПОВТОРЛИВО ЧИТАЊЕ
  • СЕРИЈАЛИЗИРА

Ајде да го разгледаме секое ниво посебно. Трошоците за спроведување на секое ниво растат речиси експоненцијално.

ПРОЧИТАЈ НЕОБВРШЕНИ - ова е најниско ниво на изолација, но во исто време и најбрзо. Трансакциите можат да ги читаат промените направени едни од други.

ПРОЧИТАЈ ПОВРЗЕНИ е следното ниво на изолација, што е компромис. Трансакциите не можат да ги читаат меѓусебните промени пред извршувањето, но можат да ги читаат сите промени направени по извршувањето.

Ако имаме долга трансакција Т1, за време на која се случувале обврзувања во трансакциите T2, T3 ... Tn, кои работеле со истите податоци како T1, тогаш кога бараме податоци во T1 ќе добиваме различен резултат секој пат. Овој феномен се нарекува неповторливо читање.

ПОВТОРЛИВО ЧИТАЊЕ — во ова ниво на изолација го немаме феноменот на неповторливо читање, поради фактот што за секое барање за читање податоци, се креира слика од податоците за резултатот и кога повторно се користат во истата трансакција, податоците од снимката се користи. Сепак, можно е да се читаат фантомски податоци на ова ниво на изолација. Ова се однесува на читање на нови редови кои биле додадени со паралелни извршени трансакции.

СЕРИЈАЛИЗИРА — највисоко ниво на изолација. Се карактеризира со тоа што податоците што се користат на кој било начин во трансакцијата (читање или менување) стануваат достапни за други трансакции само по завршувањето на првата трансакција.

Прво, да откриеме дали има изолација на операциите во трансакцијата од главната нишка. Ајде да отвориме 2 терминални прозорци.

Kill ^t

Write ^t(1)
2

TSTART
Set ^t(1)=2

Нема изолација. Една нишка гледа што прави вториот што ја отвори трансакцијата.

Ајде да видиме дали трансакциите од различни нишки гледаат што се случува внатре во нив.

Ајде да отвориме 2 терминални прозорци и да отвориме 2 трансакции паралелно.

kill ^t
TSTART
Write ^t(1)
3

TSTART
Set ^t(1)=3

Паралелните трансакции ги гледаат податоците меѓусебно. Така, го добивме наједноставното, но и најбрзото ниво на изолација, ПРОЧИТАЈТЕ НЕОБВРШЕНИ.

Во принцип, ова може да се очекува за глобалните, за кои перформансите отсекогаш биле приоритет.

Што ако ни треба повисоко ниво на изолација во операциите на глобалните земји?

Тука треба да размислите зошто воопшто се потребни нивоата на изолација и како тие функционираат.

Највисокото ниво на изолација, SERIALIZE, значи дека резултатот од трансакциите извршени паралелно е еквивалентен на нивното последователно извршување, што гарантира отсуство на судири.

Можеме да го направиме ова користејќи паметни брави во ObjectScript, кои имаат многу различни намени: можете да правите редовно, постепено, повеќекратно заклучување со командата LOCK.

Пониските нивоа на изолација се компромиси дизајнирани да ја зголемат брзината на базата на податоци.

Ајде да видиме како можеме да постигнеме различни нивоа на изолација користејќи брави.

Овој оператор ви овозможува да земете не само ексклузивни брави потребни за промена на податоците, туку таканаречени споделени брави, кои можат да земат неколку нишки паралелно кога треба да читаат податоци што не треба да се менуваат со други процеси за време на процесот на читање.

Повеќе информации за методот на двофазно блокирање на руски и англиски јазик:

Двофазно блокирање
Двофазно заклучување

Тешкотијата е што за време на трансакцијата состојбата на базата на податоци може да биде неконзистентна, но овие неконзистентни податоци се видливи за други процеси. Како да се избегне ова?

Користејќи брави, ќе создадеме прозорци за видливост во кои состојбата на базата на податоци ќе биде конзистентна. И целиот пристап до таквите прозорци на видливост на договорената состојба ќе биде контролиран со брави.

Заедничките брави на истите податоци се повторно употребливи - може да ги преземат неколку процеси. Овие брави спречуваат други процеси да ги менуваат податоците, т.е. тие се користат за формирање на прозорци со конзистентна состојба на базата на податоци.

За промена на податоците се користат ексклузивни брави - само еден процес може да преземе таква брава. Ексклузивна брава може да се преземе од:

  1. Секој процес ако податоците се бесплатни
  2. Само процесот што има споделено заклучување на овие податоци и беше првиот што побара ексклузивно заклучување.

Трансакции во InterSystems IRIS globals

Колку е потесен прозорецот за видливост, толку подолго треба да го чекаат другите процеси, но колку е поконзистентна состојбата на базата на податоци во неа.

READ_COMMITTED — Суштината на ова ниво е што гледаме само посветени податоци од други нишки. Ако податоците во друга трансакција сè уште не се извршени, тогаш ја гледаме нејзината стара верзија.

Ова ни овозможува да ја паралелизираме работата наместо да чекаме да се ослободи бравата.

Без посебни трикови, нема да можеме да ја видиме старата верзија на податоците во IRIS, па ќе мора да се задоволиме со брави.

Според тоа, ќе треба да користиме споделени брави за да дозволиме податоците да се читаат само во моменти на конзистентност.

Да речеме дека имаме база на корисници ^лице кое си префрла пари едни на други.

Момент на трансфер од лице 123 на лице 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)

Моментот на барање на износот на пари од лицето 123 пред задолжување мора да биде придружен со ексклузивен блок (по дифолт):

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

И ако треба да го прикажете статусот на сметката во вашата лична сметка, тогаш можете да користите споделена брава или воопшто да не ја користите:

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

Меѓутоа, ако претпоставиме дека операциите на базата на податоци се извршуваат речиси моментално (дозволете ми да ве потсетам дека глобалните се структура на многу пониско ниво од релациската табела), тогаш потребата за ова ниво се намалува.

ПОВТОРЛИВО ЧИТАЊЕ - Ова ниво на изолација овозможува повеќекратно читање на податоци што може да се менуваат со истовремени трансакции.

Соодветно на тоа, ќе треба да поставиме заедничка брава за читање на податоците што ги менуваме и ексклузивни заклучувања на податоците што ги менуваме.

За среќа, операторот LOCK ви овозможува детално да ги наведете сите потребни брави, од кои може да има многу, во една изјава.

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

други операции (во овој момент паралелните нишки се обидуваат да променат ^лице (123, износ), но не можат)

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

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

Кога ги наведувате бравите одделени со запирки, тие се земаат последователно, но ако го направите ова:

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

тогаш тие се земаат атомски одеднаш.

СЕРИЈАЛИЗИРАЈ — ќе мораме да поставиме брави така што на крајот сите трансакции кои имаат заеднички податоци се извршуваат последователно. За овој пристап, повеќето брави треба да бидат ексклузивни и да се преземат на најмалите области на глобалната за перформанси.

Ако зборуваме за задолжување средства во глобалното ^лице, тогаш за тоа е прифатливо само нивото на изолација SERIALIZE, бидејќи парите мора да се трошат строго последователно, инаку е можно да се потроши иста сума неколку пати.

4. Трајност

Спроведов тестови со тврдо сечење на контејнерот користејќи

docker kill my-iris

Основата добро ги поднесуваше. Не беа идентификувани никакви проблеми.

Заклучок

За глобалните, InterSystems IRIS има поддршка за трансакции. Тие се навистина атомски и сигурни. За да се обезбеди конзистентност на базата на податоци базирана на глобални, потребни се напори од програмер и употреба на трансакции, бидејќи таа нема сложени вградени конструкции како што се странските клучеви.

Нивото на изолација на глобалните без користење брави е ПРОЧИТАЈТЕ НЕКОРИСТЕНО, а кога користите брави може да се обезбеди до нивото СЕРИЈАЛИЗИРАЊЕ.

Коректноста и брзината на трансакциите на глобалните многу зависи од вештината на програмерот: колку повеќе се користат брави кои се споделуваат при читање, толку е повисоко нивото на изолација и колку потесно се земаат бравите, толку побрзи се перформансите.

Извор: www.habr.com

Додадете коментар