CodeGym /Java tanfolyam /All lectures for HU purposes /A ACID megvalósítása egy alkalmazásban: gyakorlat

A ACID megvalósítása egy alkalmazásban: gyakorlat

All lectures for HU purposes
Szint , Lecke
Elérhető

8.1 Tranzakcióazonosítók

XID-nek vagy TxID-nek van kijelölve (ha van különbség, szóljon). Az időbélyegek TxID-ként használhatók, ami a kezébe kerülhet, ha minden műveletet vissza akarunk állítani egy bizonyos időpontra. A probléma akkor merülhet fel, ha az időbélyeg nem elég részletes – akkor a tranzakciók ugyanazt az azonosítót kaphatják.

Ezért a legmegbízhatóbb lehetőség az egyedi UUID termékazonosítók létrehozása. Pythonban ez nagyon egyszerű:

>>> import uuid 
>>> str(uuid.uuid4()) 
'f50ec0b7-f960-400d-91f0-c42a6d44e3d0' 
>>> str(uuid.uuid4()) 
'd15bed89-c0a5-4a72-98d9-5507ea7bc0ba' 

Lehetőség van arra is, hogy kivonatolja a tranzakciót meghatározó adatok készletét, és ezt a hash-t TxID-ként használja.

8.2 Újrapróbálkozások

Ha tudjuk, hogy egy adott függvény vagy program idempotens, akkor ez azt jelenti, hogy meg lehet és meg is kell próbálnunk megismételni a hívását hiba esetén. És csak fel kell készülnünk arra, hogy néhány művelet hibát ad – tekintettel arra, hogy a modern alkalmazások hálózaton és hardveren vannak elosztva, a hibát nem kivételnek, hanem normának kell tekinteni. A hiba előfordulhat szerver összeomlás, hálózati hiba, távoli alkalmazások torlódása miatt. Hogyan viselkedjen az alkalmazásunk? Így van, próbáld megismételni a műveletet.

Mivel egy kódrészlet többet tud mondani, mint egy egész oldalnyi szó, használjunk egy példát annak megértésére, hogyan kell ideálisan működnie a naiv újrapróbálkozási mechanizmusnak. Ezt a Tenacity könyvtár segítségével fogom bemutatni (annyira jól megtervezett, hogy még ha nem is tervezi használni, a példa megmutatja, hogyan tervezheti meg az ismétlődési mechanizmust):

import logging
import random
import sys
from tenacity import retry, stop_after_attempt, stop_after_delay, wait_exponential, retry_if_exception_type, before_log

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)

@retry(
	stop=(stop_after_delay(10) | stop_after_attempt(5)),
	wait=wait_exponential(multiplier=1, min=4, max=10),
	retry=retry_if_exception_type(IOError),
	before=before_log(logger, logging.DEBUG)
)
def do_something_unreliable():
	if random.randint(0, 10) > 1:
    	raise IOError("Broken sauce, everything is hosed!!!111one")
	else:
    	return "Awesome sauce!"

print(do_something_unreliable.retry.statistics)

> Minden esetre elmondom: a \@retry(...) egy speciális Python szintaxis, amelyet "dekorátornak" neveznek. Ez csak egy újrapróbálkozás(...) függvény, amely becsomagol egy másik függvényt, és végrehajt valamit a végrehajtás előtt vagy után.

Amint látjuk, az újrapróbálkozásokat kreatívan meg lehet tervezni:

  • Korlátozhatja a próbálkozásokat idővel (10 másodperc) vagy a kísérletek számával (5).
  • Lehet exponenciális (azaz 2 ** valamilyen növekvő szám n ). vagy más módon (például rögzítve), hogy növelje az egyes próbálkozások közötti időt. Az exponenciális változatot "torlódási összeomlásnak" nevezik.
  • Csak bizonyos típusú hibák esetén próbálkozhat újra (IOError).
  • Az újrapróbálkozási kísérleteket megelőzheti vagy befejezheti néhány speciális bejegyzés a naplóban.

Most, hogy elvégeztük a fiatal harcos tanfolyamot, és ismerjük azokat az alapvető építőelemeket, amelyekre szükségünk van az alkalmazásoldali tranzakciókkal való munkavégzéshez, ismerkedjünk meg két módszerrel, amelyek lehetővé teszik a tranzakciók megvalósítását elosztott rendszerekben.

8.3 Speciális eszközök a tranzakciók szerelmeseinek

Csak meglehetősen általános definíciókat adok, mivel ez a téma megérdemel egy külön nagy cikket.

Kétfázisú commit (2db) . A 2pc-nek két fázisa van: egy előkészítési és egy commit fázis. Az előkészítési szakaszban minden mikroszolgáltatást felkérnek arra, hogy készüljön fel néhány atomszerűen végrehajtható adatmódosításra. Ha ezek mind készen állnak, a véglegesítési szakasz elvégzi a tényleges változtatásokat. A folyamat koordinálásához globális koordinátorra van szükség, aki zárolja a szükséges objektumokat – azaz elérhetetlenné válik a változtatások számára, amíg a koordinátor fel nem oldja azokat. Ha egy adott mikroszolgáltatás nem áll készen a változtatásokra (például nem válaszol), a koordinátor megszakítja a tranzakciót, és megkezdi a visszaállítási folyamatot.

Miért jó ez a protokoll? Az atomitást biztosítja. Ezenkívül garantálja az elszigeteltséget írás és olvasás közben. Ez azt jelenti, hogy az egyik tranzakció módosításai nem láthatók mások számára, amíg a koordinátor el nem végzi a változtatásokat. De ezeknek a tulajdonságoknak van egy hátrányuk is: mivel ez a protokoll szinkron (blokkoló), lelassítja a rendszert (annak ellenére, hogy maga az RPC hívás meglehetősen lassú). És ismét fennáll a kölcsönös blokkolás veszélye.

Saga . Ebben a mintában az elosztott tranzakciókat aszinkron helyi tranzakciók hajtják végre az összes kapcsolódó mikroszolgáltatáson keresztül. A mikroszolgáltatások eseménybuszon keresztül kommunikálnak egymással. Ha valamelyik mikroszolgáltatás nem hajtja végre a helyi tranzakcióját, más mikroszolgáltatások kompenzációs tranzakciókat hajtanak végre a változtatások visszaállítása érdekében.

A Saga előnye, hogy nincsenek objektumok blokkolva. De persze vannak árnyoldalai is.

A Saga-t nehéz hibakeresni, különösen, ha sok mikroszolgáltatásról van szó. A Saga minta másik hátránya, hogy hiányzik az olvasási izoláció. Vagyis ha az ACID-ben feltüntetett tulajdonságok fontosak számunkra, akkor a Saga nem nagyon alkalmas számunkra.

Mit látunk e két technika leírásából? Az a tény, hogy az elosztott rendszerekben az atomitásért és az izolációért az alkalmazás felelős. Ugyanez történik olyan adatbázisok használatakor, amelyek nem nyújtanak ACID-garanciát. Vagyis az olyan dolgok, mint a konfliktusok megoldása, a visszalépések, a véglegesítések és a hely felszabadítása a fejlesztő vállára esnek.

8.4 Honnan tudhatom, mikor van szükségem ACID-garanciára?

Ha nagy a valószínűsége annak, hogy a felhasználók vagy folyamatok egy bizonyos csoportja egyidejűleg ugyanazon az adatokon dolgozik .

Elnézést a banalitásért, de tipikus példa a pénzügyi tranzakciók.

Amikor a tranzakciók végrehajtásának sorrendje számít.

Képzelje el, hogy cége a FunnyYellowChat messengerről FunnyRedChat messengerre áll át, mivel a FunnyRedChat lehetővé teszi a gif küldését, de a FunnyYellowChat nem. Ön azonban nem csak a hírvivőt változtatja meg, hanem cége levelezését is átköltözteti egyik messengerről a másikra. Ezt azért csinálod, mert a programozóid lusták voltak valahol központilag dokumentálni a programokat és folyamatokat, helyette mindent különböző csatornákon publikáltak a messengerben. Igen, és az Ön értékesítői ugyanitt közzétették a tárgyalások és megállapodások részleteit. Röviden, a cége egész élete ott van, és mivel senkinek nincs ideje átvinni az egészet egy szolgáltatásba dokumentálás céljából, és az azonnali üzenetküldők keresése jól működik, úgy döntött, a romeltakarítás helyett egyszerűen lemásolja az összes üzeneteket új helyre küldeni. Fontos az üzenetek sorrendje

Amúgy a messengerben való levelezésnél általában a sorrend a fontos, de ha két ember egyszerre ír valamit ugyanabban a chatben, akkor általában nem olyan fontos, hogy kinek az üzenete jelenik meg előbb. Tehát ebben a konkrét forgatókönyvben nincs szükség ACID-re.

Egy másik lehetséges példa a bioinformatika. Ezt egyáltalán nem értem, de feltételezem, hogy az emberi genom megfejtésekor fontos a sorrend. Azt viszont hallottam, hogy a bioinformatikusok általában mindenre az ő eszközeiket használják – talán van saját adatbázisuk.

Amikor nem tudja megadni a felhasználót vagy feldolgozni elavult adatokat.

És ismét - pénzügyi tranzakciók. Őszintén szólva más példa nem jutott eszembe.

Ha a függőben lévő tranzakciók jelentős költségekkel járnak. Képzelje el, milyen problémák merülhetnek fel, ha egy orvos és egy nővér egyszerre frissíti a betegrekordot és törli egymás változásait, mivel az adatbázis nem tudja elkülöníteni a tranzakciókat. Az egészségügyi rendszer a pénzügy mellett egy másik terület, ahol az ACID garanciák általában kritikusak.

8.5 Mikor nincs szükségem ACID-re?

Amikor a felhasználók csak a személyes adataik egy részét frissítik.

Például egy felhasználó megjegyzéseket vagy cetliket hagy egy weboldalon. Vagy szerkeszti a személyes adatokat egy személyes fiókjában bármely szolgáltatónál.

Amikor a felhasználók egyáltalán nem frissítik az adatokat, hanem csak kiegészítik újakkal (hozzáfűzés).

Például egy futó alkalmazás, amely adatokat ment a futásairól: mennyit futott, mennyi ideig, útvonalat stb. Minden új futtatás új adat, a régieket pedig egyáltalán nem szerkesztik. Talán az adatok alapján elemzést kap – és erre a forgatókönyvre csak a NoSQL adatbázisok jók.

Amikor az üzleti logika nem határozza meg a tranzakciók végrehajtásának bizonyos sorrendjének szükségességét.

Valószínűleg egy Youtube-bloggernek, aki a következő élő adás során adományokat gyűjt új anyag elkészítéséhez, nem annyira fontos, hogy ki, mikor és milyen sorrendben dobott rá pénzt.

Amikor a felhasználók néhány másodpercig vagy akár percekig ugyanazon a weboldalon vagy alkalmazásablakban maradnak, és ezért valamilyen módon elavult adatokat fognak látni.

Elméletileg ezek bármelyik online hírmédia, vagy ugyanaz a Youtube. Vagy "Habr". Ha nem számít Önnek, hogy a hiányos tranzakciók átmenetileg eltárolhatók a rendszerben, akkor károsodás nélkül figyelmen kívül hagyhatja azokat.

Ha sok forrásból származó és nagy gyakorisággal frissülő adatokat összesít – például egy város parkolóhely-foglaltságának adatait, amelyek legalább 5 percenként változnak, akkor elméletileg nem lesz nagy probléma. Önnek, ha valamikor az egyik parkoló ügylete nem megy végbe. Bár persze ez attól függ, hogy pontosan mit akarsz kezdeni ezekkel az adatokkal.

Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION