Vodič za transakcije preko mikrousluga

1. Uvod

U ovom ćemo članku razmotriti opcije za implementaciju transakcije na mikroservisima.

Također ćemo provjeriti neke alternative transakcijama u scenariju distribuirane mikro usluge.

2. Izbjegavanje transakcija putem mikro usluga

Distribuirana transakcija vrlo je složen proces s puno pokretnih dijelova koji mogu propasti. Također, ako se ti dijelovi izvode na različitim strojevima ili čak u različitim podatkovnim centrima, postupak izvršavanja transakcije mogao bi postati vrlo dug i nepouzdan.

To bi moglo ozbiljno utjecati na korisničko iskustvo i ukupnu propusnost sustava. Tako jedan od najboljih načina za rješavanje problema distribuiranih transakcija je njihovo potpuno izbjegavanje.

2.1. Primjer arhitekture koja zahtijeva transakcije

Obično je mikrousluga dizajnirana tako da bude samostalna i korisna sama po sebi. Trebao bi biti u stanju riješiti neki atomski poslovni zadatak.

Ako bismo mogli podijeliti naš sustav na takve mikroservise, velika je šansa da uopće ne bismo trebali implementirati transakcije između njih.

Na primjer, razmotrimo sustav emitiranja poruka između korisnika.

The korisnik mikroservis bi se bavio korisničkim profilom (stvaranje novog korisnika, uređivanje podataka profila itd.) sa slijedećom osnovnom klasom domene:

Korisnik javne klase @Entity implementira serijski {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; @Basic privatni naziv niza; @Basic private String prezime; @Basic private Instant lastMessageTime; }

The poruka mikro servis bi se bavio emitiranjem. Inkapsulira entitet Poruka i sve oko njega:

Poruka javne klase @Entity implementira serijski {@Id @GeneratedValue (strategy = GenerationType.AUTO) private long id; @Basic private long userId; @Basic private String sadržaj; @Basic private Instant messageTimestamp; }

Svaka mikrousluga ima svoju bazu podataka. Primijetite da se ne referiramo na entitet Korisnik od entiteta Poruka, jer korisničkim klasama nije dostupan s poruka mikrousluga. Korisnika upućujemo samo na ID.

Sada Korisnik entitet sadrži lastMessageTime polje jer na njezinom profilu želimo prikazati podatke o vremenu posljednje aktivnosti korisnika.

Međutim, da biste dodali novu poruku korisniku i ažurirali je lastMessageTime, sada bismo morali implementirati transakciju putem mikrousluga.

2.2. Alternativni pristup bez transakcija

Možemo izmijeniti arhitekturu mikrousluga i ukloniti polje lastMessageTime od Korisnik entitet.

Tada bismo to vrijeme mogli prikazati u korisničkom profilu izdavanjem zasebnog zahtjeva za mikroservis poruka i pronalaženjem maksimuma messageTimestamp vrijednost za sve poruke ovog korisnika.

Vjerojatno, ako poruka mikroservis je pod velikim opterećenjem ili čak ne radi, nećemo moći prikazati vrijeme posljednje poruke korisnika na njezinom profilu.

Ali to bi moglo biti prihvatljivije od neuspjeha u distribuciji transakcije za spremanje poruke samo zato što korisnička mikroservis nije reagirao na vrijeme.

Postoje, naravno, i složeniji scenariji kada moramo implementirati poslovni proces u više mikroservisa i ne želimo dopustiti nedosljednost između tih mikroservisa.

3. Dvofazni protokol urezivanja

Dvofazni protokol urezivanja (ili 2PC) je mehanizam za implementaciju transakcije kroz različite softverske komponente (više baza podataka, redovi poruka itd.)

3.1. Arhitektura 2PC

Jedan od važnih sudionika u distribuiranoj transakciji je koordinator transakcije. Distribuirana transakcija sastoji se od dva koraka:

  • Pripremna faza - tijekom ove faze svi sudionici transakcije pripremaju se za predaju i obavještavaju koordinatora da su spremni izvršiti transakciju
  • Faza predavanja ili vraćanja - tijekom ove faze koordinator transakcije izdaje naredbu predavanja ili vraćanja svim učesnicima

Problem s 2PC je u tome što je prilično spor u usporedbi s vremenom rada jedne mikro usluge.

Koordinacija transakcija između mikro usluga, čak i ako su na istoj mreži, doista može usporiti sustav, pa se ovaj pristup obično ne koristi u scenariju velikog opterećenja.

3.2. XA Standard

XA standard je specifikacija za provođenje 2PC distribuiranih transakcija kroz prateće resurse. Bilo koji aplikacijski poslužitelj kompatibilan s JTA-om (JBoss, GlassFish itd.) Podržava ga izravno.

Resursi koji sudjeluju u distribuiranim transakcijama mogu biti, na primjer, dvije baze podataka dviju različitih mikroservisa.

Međutim, da bi se iskoristio ovaj mehanizam, resursi se moraju rasporediti na jednu JTA platformu. To nije uvijek izvedivo za arhitekturu mikro usluga.

3.3. REST-AT standardni nacrt

Drugi predloženi standard je REST-AT, koji je RedHat prošao kroz određeni razvoj, ali još uvijek nije izašao iz faze nacrta. Međutim, to podržava WildFly poslužitelj aplikacija izravno.

Ovaj standard omogućuje upotrebu aplikacijskog poslužitelja kao koordinatora transakcija sa određenim REST API-jem za stvaranje i pridruživanje distribuiranih transakcija.

RESTful web usluge koje žele sudjelovati u dvofaznoj transakciji također moraju podržavati određeni REST API.

Nažalost, da bismo distribuiranu transakciju premostili na lokalne resurse mikroservisa, još uvijek moramo te resurse rasporediti na jednu JTA platformu ili riješiti ne trivijalni zadatak pisanja ovog mosta.

4. Eventualna dosljednost i kompenzacija

Daleko je jedan od najprihvatljivijih modela postupanja s dosljednošću u mikrouslugama eventualna dosljednost.

Ovaj model ne provodi distribuirane ACID transakcije na mikroservisima. Umjesto toga, predlaže korištenje nekih mehanizama kojima se osigurava da će sustav na kraju biti dosljedan u nekom trenutku u budućnosti.

4.1. Slučaj eventualne dosljednosti

Na primjer, pretpostavimo da moramo riješiti sljedeći zadatak:

  • registrirati korisnički profil
  • obavite automatsku provjeru pozadine da li korisnik stvarno može pristupiti sustavu

Drugi je zadatak osigurati, na primjer, da ovom korisniku iz nekog razloga nije zabranjen pristup našim poslužiteljima.

Ali moglo bi potrajati, a mi bismo ga željeli izdvojiti u zasebnu mikroservisu. Ne bi bilo razumno držati korisnika toliko dugo samo da se zna da je uspješno registrirana.

Jedan od načina da se to riješi bio bi pristup koji se temelji na porukama, uključujući naknadu. Razmotrimo sljedeću arhitekturu:

  • the korisnik mikroservis koji je zadužen za registraciju korisničkog profila
  • the validacija mikroservis sa zadatkom da izvrši provjeru pozadine
  • platforma za razmjenu poruka koja podržava trajne redove

Platforma za razmjenu poruka može osigurati postojanje poruka koje šalju mikroservisi. Tada bi se isporučivali naknadno ako prijemnik trenutno nije dostupan

4.2. Sretan scenarij

U ovoj bi arhitekturi sretan scenarij bio:

  • the korisnik mikroservis registrira korisnika spremajući podatke o njoj u njegovu lokalnu bazu podataka
  • the korisnik mikroservis označava ovog korisnika zastavicom. To bi moglo značiti da ovaj korisnik još nije potvrđen i da nema pristup punoj funkcionalnosti sustava
  • korisniku se šalje potvrda o registraciji s upozorenjem da nisu sve funkcije sustava odmah dostupne
  • the korisnik mikroservis šalje poruku na validacija mikroservis za provjeru pozadine korisnika
  • the validacija microservice pokreće provjeru pozadine i šalje poruku na korisnik mikrousluga s rezultatima provjere
    • ako su rezultati pozitivni, korisnik mikroservis deblokira korisnika
    • ako su rezultati negativni, korisnik microservice briše korisnički račun

Nakon što smo prošli sve ove korake, sustav bi trebao biti u dosljednom stanju. Međutim, činilo se da je korisnički entitet neko vrijeme bio u nekompletnom stanju.

Posljednji korak, kada korisnička mikro usluga uklanja nevaljani račun, je faza naknade.

4.3. Scenariji neuspjeha

Sada razmotrimo neke scenarije neuspjeha:

  • ako je validacija mikroservisu nije dostupan, tada platforma za razmjenu poruka sa svojom postojanom funkcionalnošću reda osigurava da validacija microservice će ovu poruku primiti kasnije
  • pretpostavimo da platforma za razmjenu poruka zakaže, a zatim korisnik mikrousluga pokušava ponovno poslati poruku kasnije, na primjer, zakazanom skupnom obradom svih korisnika koji još nisu provjereni
  • ako je validacija mikroservis prima poruku, provjerava valjanost korisnika, ali ne može poslati odgovor natrag zbog neuspjeha platforme za razmjenu poruka, validacija mikroservis također pokušava poslati poruku kasnije
  • ako se jedna od poruka izgubila ili se dogodio neki drugi kvar, korisnik mikroservis pronalazi sve neovlaštene korisnike planiranom skupnom obradom i ponovno šalje zahtjeve za provjeru valjanosti

Čak i ako su neke poruke izdane više puta, to ne bi utjecalo na dosljednost podataka u bazama podataka mikroservisa.

Pažljivim razmatranjem svih mogućih scenarija otkaza možemo osigurati da naš sustav udovolji uvjetima eventualne dosljednosti. Istodobno, ne bismo se trebali baviti skupim distribuiranim transakcijama.

Ali moramo biti svjesni da je osiguravanje konačne dosljednosti složen zadatak. Nema jedinstveno rješenje za sve slučajeve.

5. Zaključak

U ovom smo članku razgovarali o nekim mehanizmima za provođenje transakcija na mikroservisima.

Također smo istražili i neke alternative za obavljanje ovog stila transakcija.