Teoria IT. Transakcje

By 24 November 2015 July 2nd, 2016 Teoria IT

O transakc­jach być może słysza­łaś już w kon­tekś­cie baz danych — jest to jeden z najbardziej rozpowszech­nionych przykładów. Postaramy się odpowiedzieć czym są transakc­je, jak wpły­wa­ją na codzi­en­ną pracę z kodem oraz jak korzys­tać z nich bezpiecznie.

#Teo­ri­aIT to wpisy, które rozsz­erzą Two­ja wiedzę o teorię, przy­dat­na znacznie częś­ciej na roz­mowach kwal­i­fika­cyjnych niż w codzi­en­nej pra­cy. Mamy nadzieję, że przy­go­towane przez nas posty uznasz za ciekawe i dzię­ki nim Świat IT będzie miał dla Ciebie mniej tajemnic.

Czym są transakcje

Transakc­ja to w ogól­nym uję­ciu zbiór oper­acji, które zmieni­a­ją stan sys­te­mu (np. dane prze­chowywane w tabelach w przy­pad­ku baz danych lub para­me­try aplikacji) w kilku krokach, i tylko wyko­nanie wszys­t­kich tych kroków może być uznane za sukces. Jeśli któryś z kroków się nie powiedzie, należy wyco­fać wszys­tkie zmi­any doko­nane w ramach transakcji.

Najprost­szą analogią do rzeczy­wis­toś­ci są zwykłe zakupy w sklepie z obsługą — pier­wszym krok­iem jest poprosze­nie obsłu­gi o pro­dukt, drugim wydanie tego pro­duk­tu, trzec­im wygen­erowanie paragonu i czwartym zapła­ta. Niepowodze­nie które­gokol­wiek z nich (np. zapom­nieliśmy port­fela i nie może­my zapłacić) powodu­je konieczność anu­lowa­nia wszys­t­kich poprzed­nich czynności.

Zakończe­nie transakcji powodze­niem prowadzi do tzw. com­mi­ta — zapisa­nia wszys­t­kich zmi­an w ‚głównym’ stanie i udostęp­nie­nie ich innym w przyszłoś­ci. Niepowodze­nie transakcji wyma­ga tzw. roll­bac­ka — przy­wróce­nia stanu sprzed transakcji, czyli anu­lowa­nia wszys­t­kich wprowad­zonych do tej pory zmian.

Systemy transakcyjne

Choć najpraw­dopodob­niej z transakc­ja­mi spotkasz się głównie w kon­tekś­cie baz danych, ist­nieje także bardziej abstrak­cyjne poję­cie sys­temów transak­cyjnych. Są to aplikac­je, które prze­chowu­ją wewnętrzny stan i zarządza­ją nim w sposób transak­cyjny — izolu­jąc poszczególne zmi­any od siebie. Sys­te­my takie mogą być rozpros­zone, mogą też składać się z wielu aplikacji i podsys­temów. Weźmy np. sys­tem bankowy do obsłu­gi przelewów. Sys­tem taki, real­izu­jąc przelew, musi obniżyć sal­do oso­bie, która wysyła przelew, pod­nieść sal­do oso­bie otrzy­mu­jącej oraz w razie potrze­by zwery­fikować reguły bez­pieczeńst­wa, zapisać infor­ma­c­je na liś­cie transakcji, powiadomić odpowied­nie sys­te­my banku cen­tral­nego. Wszys­tko to musi się odby­wać w ramach jed­nej transakcji — niepowodze­nie które­gokol­wiek kroku musi skutkować wyco­faniem wszys­t­kich. Pra­ca z duży­mi sys­tema­mi transak­cyjny­mi jest jed­ną z bardziej wyma­ga­ją­cych i jed­nocześnie ciekawszych wyzwań, jakie mogą stać przed pro­gramistą :) Pod koniec zna­jdziesz przykłady narzędzi, które są pomoc­ne w real­i­zowa­niu tego typu aplikacji.

ACID

ACID to akro­n­im od ang­iel­s­kich słów atom­ic­i­ty — con­sis­ten­cy — iso­la­tion — dura­bil­i­ty. Są to cechy oczeki­wane od każdego sys­te­mu transak­cyjnego, w szczegól­noś­ci od baz danych. Pozwala­ją one czynić pewne założe­nia na etapie pro­jek­towa­nia i imple­men­tacji aplikacji i sku­pi­ać się na log­ice biz­ne­sowej, a nie zarządzaniem środowiskiem, w którym może ist­nieć wiele transakcji.

Atom­ic­i­ty — (pol. ato­m­owość) niepodziel­ność transakcji, transakc­ja może albo zakończyć się w całoś­ci powodze­niem albo nie. Dzię­ki temu mamy gwaranc­je, że albo wyko­nane zostaną wszys­tkie oper­ac­je, albo żad­na z nich.

Con­sis­ten­cy — (pol. spójność)  utrzy­manie spójnoś­ci w całym kon­tekś­cie, jakiego doty­czy transakc­ja. Inny­mi słowy wszys­tkie oper­ac­je wykony­wane w ramach transakcji muszą prowadz­ić do spójnego stanu, tzn. takiego, który moż­na scal­ić z inny­mi zmi­ana­mi i który jest zgod­ny z zasada­mi systemu.

Iso­la­tion — (pol. izo­lac­ja)  rozdzie­le­nie pomiędzy transakc­ja­mi — zmi­any i oper­ac­je wykony­wane w jed­nej transakcji domyśl­nie nie mogą wpły­wać na dane i stan przetwarzany w drugiej transakcji.

Dura­bil­i­ty — (pol. trwałość) o ile transakc­ja zakończy się sukce­sem, zmi­ana stanu, która w niej zaszła, powin­na być prze­chowywana i stała.

Przykłady implementacji

Ta sekc­ja pokazu­je kil­ka przykładów uży­cia tech­nologii związanych z transakc­ja­mi — ponieważ o każdej z nich moż­na napisać książkę (i częs­to już to zro­biono), ograniczymy się do pokaza­nia przykładu uży­cia oraz odesła­nia osób zain­tere­sowanych do innych źródeł.

JTA, Spring

W Javie ist­nieje stan­dar­d­owy sposób zarządza­nia transakc­ja­mi, także rozpros­zony­mi, pod nazwą JTA — Java Trans­ac­tion API. Podob­nie jak JPA, defini­u­je on API, które może być imple­men­towane przez dowol­ną bib­liotekę, której zde­cy­du­je­my się użyć. Prob­le­mem do tej pory był fakt, że transakc­je te były respek­towane tylko w ramach EJB (uległo to zmi­an­ie w Javie EE 7). Z tego powodu Spring posi­a­da włas­ny sys­tem zarządza­nia transakc­ja­mi, który jed­nak jest zgod­ny (i łat­wo inte­growal­ny) z JTA.

Jak się zapewne domyślasz, w tym wypad­ku sama musisz zaim­ple­men­tować logikę do ‘odwraca­nia’ transakcji — jest to zależne od sys­te­mu i cza­sem niemożli­we w 100% (np. jeśli już został wysłany mail lub powiadomiony zewnętrzny sys­tem — nie da się takiej czyn­noś­ci ‘cofnąć’, trze­ba zaradz­ić jej skutkom — wysłać maila z przeprosi­na­mi, anu­lować transakc­je w innym sys­temie itp). Pole­camy szczegól­nie opis z doku­men­tacji Springa — omaw­ia on cały kon­cept zarządza­nia transakc­ja­mi w Springu i stosowne inter­fe­j­su oraz adno­tac­je (z których głów­na to @Transactional). Transakc­je w Springu są imple­men­towane z wyko­rzys­taniem AOP.

Tuto­r­i­al Spring o korzys­ta­niu z transakcji w połącze­niu z JTA

Opis mech­a­niz­mu transakcji w Springu

JPA i bazy danych

Więk­szość współczes­nych baz danych domyśl­nie dzi­ała w opar­ciu o transakc­je, nawet bez naszej wiedzy — domyśl­ny tryb to otwieranie transakcji przed każdym zapy­taniem SQL i jej com­mi­towanie po wyko­na­niu danego zapy­ta­nia. Imple­men­tac­je JPA korzys­ta­ją z tych mech­a­nizmów inte­gru­jąc je jed­nocześnie z opisanym wcześniej JTA — dzię­ki temu aplikac­je Javy mogą łączyć oper­ac­je na bazie danych z inny­mi dzi­ała­ni­a­mi w ramach jed­nej transakcji. Z transakcji korzys­tamy np. uży­wa­jąc Springowej adno­tacji @Transactional, lub — jeśli korzys­tamy bezpośred­nio z Hiber­nate — korzys­ta­jąc z obiek­tów imple­men­tu­ją­cych org.hibernate.Session.

Transakc­je może­my także obsługi­wać z poziomu języ­ka SQL, więcej zna­jdziesz w tuto­ri­alu tuto­ri­al­s­point oraz w doku­men­tacji MySQL.

Transakcje rozproszone

W tym przy­pad­ku mamy dwie możli­woś­ci — samodziel­nej imple­men­tacji jed­nego z algo­ryt­mów lub sko­rzys­ta­nia z gotowych rozwiązań. Gorą­co pole­camy tą drugą opcję, jed­nak mimo tego warto zapoz­nać się z pod­stawa­mi algo­ryt­mów, które wykorzystują.

Two-phase commit

Jest to jeden z pier­wszych i prost­szych pro­tokołów pozwala­ją­cych zarządzać zdal­ny­mi transakc­ja­mi. Lid­er wysyła prośbę do wszys­t­kich zewnętrznych sys­temów o doko­nanie pewnej zmi­any — może to być np. wyko­nanie określonej oper­acji, ale bez com­mi­towa­nia jej. Następ­nie zewnętrzne sys­te­my (w algo­ryt­mie tym nazy­wane kohortą) odsyła­ją odpowiedź z infor­ma­cją czy udało się wykon­ać oper­ację czy nie. Lid­er na postaw­ie tych infor­ma­cji pode­j­mu­je decyz­je, czy całość ma zostać zaak­cep­towana czy odrzu­cona, po czym wysyła stosowną infor­ma­cję do kohorty.

Protokół Paxos

Jest to tak naprawdę gru­pa kilku pro­tokołów do osią­ga­nia kon­sen­susu w rozpros­zonych sys­temach, które mogą być wyko­rzysty­wane także do zarządza­nia zdal­ną transakcją. Ich głównym wyróżnikiem jest możli­wość bal­an­sowa­nia pomiędzy różny­mi cecha­mi — szy­bkoś­cią, pewnoś­cią osiąg­nię­cia kon­sen­susu, odpornoś­cią na błędy i prob­le­my w komu­nikacji itp. Dzię­ki temu mają sze­rok­ie zas­tosowanie w różnych sys­temach — przykład­owo imple­men­tac­ja o nazwie Apache Mesos jest wyko­rzysty­wana w tak różnych sys­temach jak eBay, Airbnb czy Twitter.

Opis na stron­ie Goodmath

Strona Wikipedii

Apache Zookeeper

Apache Zookeep­er to narzędzie do koor­dynowa­nia rozpros­zonych sys­temów — opiera się ono na rozpros­zonych lock­ach i koor­dynowa­niu dostępu do zasobów, także może zostać wyko­rzys­tane do zarządza­nia transakc­ja­mi rozproszonymi.

Ofic­jal­na strona

Podsumowanie

Transakc­je, to oper­ac­je, które moż­na pod­sumować: wykona się wszystko,albo nic. Takie pode­jś­cie może okazać się korzystne dla wielu rozwiązań, w szczegól­noś­ci, gdy oper­ac­je, które obsługu­je­my są wieloetapowe. Oczy­wiś­cie warto mieć świado­mość, że nie każde dzi­ałanie zawarte w transakcji moż­na cofnąć (jak wspom­ni­aną już przez nas wysyłkę e‑mail), dlat­ego pro­jek­tu­jąc transakc­je trze­ba dokład­nie znać jej przebieg.