Трансакције у ИнтерСистемс ИРИС глобалима

Трансакције у ИнтерСистемс ИРИС глобалимаИнтерСистемс ИРИС ДБМС подржава занимљиве структуре за складиштење података - глобалне. У суштини, ово су кључеви на више нивоа са разним додатним погодностима у облику трансакција, брзим функцијама за прелазак на стабла података, бравама и сопственим ОбјецтСцрипт језиком.

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

Дрвеће. Део 1
Дрвеће. Део 2
Ретки низови. део 3

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

Као што је познато из теорије релационих база података, добра имплементација трансакција мора да задовољи захтеве КИСЕЛИНА:

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

Ц - Конзистентност. Након што се трансакција заврши, логичко стање базе података мора бити интерно конзистентно. На много начина овај захтев се односи на програмера, али у случају СКЛ база података такође се односи на стране кључеве.

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

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

Глобалне вредности су нерелационе структуре података. Дизајнирани су да раде супер брзо на веома ограниченом хардверу. Хајде да погледамо имплементацију трансакција у глобалима користећи званична ИРИС доцкер слика.

За подршку трансакцијама у ИРИС-у, користе се следеће команде: ТСТАРТ, ТЦОММИТ, ТРОЛЛБАЦК.

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

Ова команда је скоро еквивалентна принудном гашењу, јер шаље СИГКИЛЛ сигнал да одмах заустави процес.

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

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. Доследност

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

На пример, имамо глобалну ^особу, у којој чувамо личности и користимо ТИН као кључ.

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

Да бисмо имали брзу претрагу по презимену и имену, направили смо кључ ^индек.

^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. Изолација

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

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

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

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

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

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

СКЛ дефинише 4 нивоа изолације:

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

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

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

ПРОЧИТАЈТЕ ПРЕДАНО је следећи ниво изолације, који је компромис. Трансакције не могу да читају измене једне друге пре урезивања, али могу да читају све промене направљене након урезивања.

Ако имамо дугу трансакцију Т1, током које је извршено урезивање у трансакцијама Т2, Т3 ... Тн, која је радила са истим подацима као Т1, онда ћемо приликом захтевања података у Т1 сваки пут добити другачији резултат. Ова појава се назива непоновљиво читање.

ЧИТАЊЕ ЗА ПОНАВЉАЊЕ — у овом нивоу изолације немамо феномен непоновљивог читања, због чињенице да се за сваки захтев за читање података креира снимак резултата резултата и када се поново користи у истој трансакцији, подаци из снимка се користи. Међутим, могуће је читати фантомске податке на овом нивоу изолације. Ово се односи на читање нових редова који су додати паралелно извршеним трансакцијама.

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

Прво, хајде да схватимо да ли постоји изолација операција у трансакцији од главне нити. Хајде да отворимо 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

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

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

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

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

Највиши ниво изолације, СЕРИАЛИЗЕ, значи да је резултат трансакција које се извршавају паралелно еквивалентан њиховом секвенцијалном извршавању, што гарантује одсуство колизија.

То можемо да урадимо помоћу паметних брава у ОбјецтСцрипт-у, које имају много различитих употреба: можете да урадите редовно, инкрементално, вишеструко закључавање помоћу команде ЛОЦК.

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

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

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

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

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

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

Користећи браве, направићемо прозоре видљивости у којима ће стање базе података бити конзистентно. А сав приступ таквим прозорима видљивости уговореног стања биће контролисан бравама.

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

Ексклузивне браве се користе за промене података - само један процес може да преузме такво закључавање. Ексклузивну браву могу преузети:

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

Трансакције у ИнтерСистемс ИРИС глобалима

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

РЕАД_ЦОММИТТЕД — суштина овог нивоа је да видимо само урезане податке из других нити. Ако подаци у другој трансакцији још нису уписани, онда видимо његову стару верзију.

Ово нам омогућава да упоредимо рад уместо да чекамо да се закључавање отпусти.

Без посебних трикова нећемо моћи да видимо стару верзију података у ИРИС-у, па ћемо морати да се задовољимо бравама.

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

Рецимо да имамо корисничку базу ^особу која преноси новац једни другима.

Тренутак трансфера од особе 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 +^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))

онда се узимају атомски одједном.

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

Ако говоримо о задуживању средстава у глобалном ^особу, онда је за њега прихватљив само ниво изолације СЕРИАЛИЗЕ, јер се новац мора трошити стриктно секвенцијално, иначе је могуће потрошити исти износ више пута.

4. Трајност

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

docker kill my-iris

База их је добро подносила. Нису идентификовани никакви проблеми.

Закључак

За глобалне, ИнтерСистемс ИРИС има подршку за трансакције. Они су заиста атомски и поуздани. Да би се обезбедила конзистентност базе података заснована на глобалима, потребни су напори програмера и коришћење трансакција, пошто она нема сложене уграђене конструкције као што су страни кључеви.

Ниво изолације глобала без коришћења брава је РЕАД УНЦОММИТЕД, а када се користе браве може се обезбедити до нивоа СЕРИАЛИЗЕ.

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

Извор: ввв.хабр.цом

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