paint-brush
Megbízható üzenetküldés az elosztott rendszerekbenáltal@fairday
37,185 olvasmányok
37,185 olvasmányok

Megbízható üzenetküldés az elosztott rendszerekben

által Aleksei8m2024/03/18
Read on Terminal Reader
Read this story w/o Javascript

Túl hosszú; Olvasni

Megbízható, magas rendelkezésre állású, méretezhető elosztott rendszer felépítéséhez meghatározott technikák, elvek és minták betartása szükséges.
featured image - Megbízható üzenetküldés az elosztott rendszerekben
Aleksei HackerNoon profile picture

Kettős írási probléma

Megbízható, magas rendelkezésre állású, méretezhető elosztott rendszer felépítéséhez meghatározott technikák, elvek és minták betartása szükséges. Az ilyen rendszerek tervezése számtalan kihívással jár. A legelterjedtebb és alapvető problémák közé tartozik a kettős írási probléma .


A „kettős írási probléma” egy olyan kihívás, amely elosztott rendszerekben merül fel, főleg akkor, ha több adatforrással vagy adatbázissal foglalkoznak, amelyeket szinkronban kell tartani. Arra utal, hogy nehéz biztosítani, hogy az adatok változásait következetesen beírják a különböző adattárakba, például adatbázisokba vagy gyorsítótárakba, anélkül, hogy olyan problémákat okoznának, mint az adatok következetlenségei, ütközései vagy teljesítménybeli szűk keresztmetszetek.


A mikroszolgáltatások architektúrája és szolgáltatásonkénti mintaadatbázisa számos előnnyel jár, mint például a független üzembe helyezés és méretezés, az elszigetelt hibák és a fejlesztési sebesség potenciális fellendítése. A műveletek azonban változtatásokat igényelnek több mikroszolgáltatás között, ami arra kényszeríti Önt, hogy gondolkodjon egy megbízható megoldáson a probléma kezelésére.

Majdnem valós példa

Tekintsünk egy olyan forgatókönyvet, amelyben a tartományunk magában foglalja a hitelkérelmek elfogadását, elbírálását, majd értesítő riasztások küldését az ügyfeleknek.


Az egységes felelősség elvének, a Conway-törvénynek és a tartományvezérelt tervezési megközelítésnek a szellemében több esemény-viharos munkamenet után az egész tartományt három altartományra osztották, meghatározott korlátos kontextusokkal, egyértelmű határokkal, tartománymodellekkel és mindenütt jelenlévő nyelvvel.


Az első feladata az új hitelkérelmek beépítése és összeállítása. A második rendszer ezeket a pályázatokat értékeli, és a megadott adatok alapján dönt. Ez az értékelési folyamat, beleértve a KYC/KYB-t, a csalás elleni és a hitelkockázati ellenőrzéseket is, időigényes lehet, ezért több ezer kérelem egyidejű kezelésének képességére van szükség. Következésképpen ezt a funkciót egy saját adatbázissal rendelkező, dedikált mikroszolgáltatásra delegálták, amely lehetővé teszi a független méretezést.

Ezen túlmenően ezeket az alrendszereket két különböző csapat kezeli, amelyek mindegyike saját kiadási ciklussal, szolgáltatásszint-szerződéssel (SLA) és méretezhetőségi követelményekkel rendelkezik.


Végül egy speciális értesítési szolgáltatás is működik, amely riasztásokat küld az ügyfeleknek.



Itt található a rendszer elsődleges használati esetének finomított leírása:

  1. Az ügyfél hitelkérelmet nyújt be.
  2. A Hiteligénylési Szolgálat az új kérelmet „Függőben” státusszal rögzíti, és a kérelem Értékelési Szolgálat felé történő továbbításával elindítja az elbírálási folyamatot.
  3. Az Értékelő Szolgálat a beérkező hitelkérelmet értékeli, majd a döntésről tájékoztatja a Hiteligénylő Szolgálatot.
  4. A határozat kézhezvételekor a Hiteligénylési Szolgálat ennek megfelelően frissíti a hiteligénylés állapotát, és elindítja az Értesítési szolgáltatást, hogy tájékoztassa az ügyfelet az eredményről.
  5. Az Értesítési szolgáltatás feldolgozza ezt a kérést, és értesítéseket küld az ügyfélnek e-mailben, SMS-ben vagy más preferált kommunikációs módokon, az ügyfél beállításai szerint.


Első pillantásra meglehetősen egyszerű és primitív rendszer, de nézzük meg, hogyan dolgozza fel a Hiteligénylés szolgáltatás a hiteligénylés benyújtása parancsot.


A szolgáltatási interakciók két megközelítését tekinthetjük:

  1. Első-helyi véglegesítés, majd közzététel: Ebben a megközelítésben a szolgáltatás frissíti a helyi adatbázisát (commit), majd eseményt vagy üzenetet tesz közzé más szolgáltatások számára.

  2. Első közzététel, majd helyi véglegesítés: Ez a módszer egy esemény vagy üzenet közzétételét foglalja magában, mielőtt a változtatásokat véglegesítené a helyi adatbázisban.


Mindkét módszernek megvannak a maga hátrányai, és csak részben hibabiztosak az elosztott rendszerekben történő kommunikációhoz.


Ez az első megközelítés alkalmazásának szekvenciadiagramja.


Először – Helyi – Kötelezettség, majd – Közzététel


Ebben a forgatókönyvben a kölcsönigénylési szolgáltatás a First-Local-Commit-Then-Publish megközelítést alkalmazza, ahol először végrehajt egy tranzakciót, majd megpróbál értesítést küldeni egy másik rendszernek. Ez a folyamat azonban meghibásodhat, ha például hálózati problémák vannak, az Értékelési szolgáltatás nem érhető el, vagy a Hiteligénylési szolgáltatás Memória megtelt (OOM) hibát észlel, és összeomlik. Ilyen esetekben az üzenet elveszne, és az Értékelés az új hiteligénylés értesítése nélkül maradna, hacsak nem hajtanak végre további intézkedéseket.


És a második.

Először-Közzététel-Majd-Helyi Végrehajtás
Az első közzététel, majd a helyi kötelezettségvállalás forgatókönyve esetén a kölcsönigénylési szolgáltatás jelentősebb kockázatokkal néz szembe. Előfordulhat, hogy értesíti az Értékelési szolgáltatást egy új alkalmazásról, de nem tudja helyileg menteni a frissítést olyan problémák miatt, mint például adatbázis-problémák, memóriahibák vagy kódhibák. Ez a megközelítés jelentős inkonzisztenciákhoz vezethet az adatokban, ami komoly problémákat okozhat attól függően, hogy a Hitelbírálati szolgáltatás hogyan kezeli a beérkező kérelmeket.


Ezért olyan megoldást kell azonosítanunk, amely robusztus mechanizmust kínál az események külső fogyasztók számára történő közzétételére. Mielőtt azonban belemerülnénk a lehetséges megoldásokba, először tisztázni kell az elosztott rendszerekben elérhető üzenetküldési garanciák típusait.

Üzenet kézbesítési garanciák

Négyféle garanciát tudunk elérni.

  1. Nincs garancia
    Nincs garancia arra, hogy az üzenetet a célállomásra kézbesítik. A First-Local-Commit-Then-Publish megközelítés pontosan erről szól. A fogyasztók egyszer, többször vagy egyáltalán nem kaphatnak üzeneteket.

  2. Legfeljebb egyszeri szállítás
    Legfeljebb egyszeri kézbesítés azt jelenti, hogy az üzenetet legfeljebb 1 alkalommal kézbesítik a célállomásra. A First-Local-Commit-Then-Publish megközelítés ilyen módon is megvalósítható az egyes értékű próbálkozások újrapróbálkozási politikájával.

  3. Legalább egyszer kézbesítés\A fogyasztók minden üzenetet megkapnak és feldolgoznak, de előfordulhat, hogy ugyanazt az üzenetet többször is megkapják.

  4. Pontosan egyszeri kézbesítés\Pontosan egyszeri kézbesítés azt jelenti, hogy a fogyasztó ténylegesen egyszer kapja meg az üzenetet.
    Technikailag a Kafka-tranzakciókkal és a termelő és fogyasztó konkrét idempotens megvalósításával lehet elérni.


A legtöbb esetben a „legalább egyszeri” kézbesítési garanciák számos problémát megoldanak azáltal, hogy az üzeneteket legalább egyszer kézbesítik, de a fogyasztóknak tehetetlennek kell lenniük. Az elkerülhetetlen hálózati hibák miatt azonban minden fogyasztói logikának idempotensnek kell lennie, hogy elkerülje a duplikált üzenetek feldolgozását, függetlenül a gyártó garanciáitól. Ezért ez a követelmény nem annyira hátrány, mint inkább a valóságot tükrözi.

Megoldások

Számos megoldás létezik erre a problémára, amelyeknek megvannak a maga előnyei és hátrányai.

Kétfázisú véglegesítés

A Wikipédia szerint a Two-Phase Commit (2PC) egy elosztott tranzakciós protokoll, amelyet a számítástechnikában és az adatbázis-kezelő rendszerekben használnak az elosztott tranzakciók konzisztenciájának és megbízhatóságának biztosítására. Olyan helyzetekre tervezték, amikor több erőforrásnak (pl. adatbázisnak) kell részt vennie egyetlen tranzakcióban, és biztosítja, hogy vagy mindegyik végrehajtja a tranzakciót, vagy mindegyik megszakítja azt, ezáltal megőrzi az adatok konzisztenciáját. Pontosan úgy hangzik, amire szükségünk van, de a kétfázisú véglegesítésnek számos hátránya van:

  • Ha az egyik részt vevő erőforrás nem válaszol, vagy meghibásodást tapasztal, a teljes folyamat blokkolható a probléma megoldásáig. Ez potenciális teljesítmény- és rendelkezésre állási problémákhoz vezethet.
  • A kétfázisú véglegesítés nem biztosít beépített hibatűrési mechanizmusokat. Külső mechanizmusokra vagy kézi beavatkozásra támaszkodik a hibák kezelésére.
  • Nem minden modern adatbázis támogatja a kétfázisú véglegesítést.

Megosztott adatbázis

A mikroszolgáltatási architektúra legszembetűnőbb megoldása egy minta (vagy akár néha anti-minta) alkalmazása – egy megosztott adatbázis. Ez a megközelítés nagyon intuitív, ha tranzakciós konzisztenciára van szüksége a különböző adatbázisok több táblájában, csak egyetlen megosztott adatbázist használjon ezekhez a mikroszolgáltatásokhoz.


Ennek a megközelítésnek a hátrányai közé tartozik az egyetlen hibapont bevezetése, a független adatbázis-méretezés gátlása, valamint a speciális követelményeknek és használati eseteknek leginkább megfelelő különböző adatbázis-megoldások használatának korlátozása. Ezenkívül a mikroszolgáltatási kódbázisok módosítására lenne szükség az elosztott tranzakciók ilyen formájának támogatásához.

Tranzakciós kimenő postafiók

A " tranzakciós kimenő postafiók " egy olyan tervezési minta, amelyet elosztott rendszerekben használnak, hogy megbízható üzenettovábbítást biztosítsanak még megbízhatatlan üzenetküldő rendszerek esetén is. Ez magában foglalja az események tárolását egy kijelölt „OutboxEvents” táblában, ugyanazon a tranzakción belül, mint maga a művelet. Ez a megközelítés jól illeszkedik a relációs adatbázisok ACID tulajdonságaihoz. Ezzel szemben sok No-SQL adatbázis nem támogatja teljes mértékben az ACID tulajdonságokat, ehelyett a CAP tétel és a BASE filozófia elveit választják, amelyek a rendelkezésre állást és az esetleges konzisztenciát helyezik előtérbe a szigorú konzisztenciával szemben.


A tranzakciós kimenő postafiók legalább egyszeri garanciát nyújt, és többféle megközelítéssel is megvalósítható:

  1. Tranzakciós napló farka

  2. Szavazás kiadója


A tranzakciónapló-farok megközelítés magában foglalja az adatbázis-specifikus megoldások, például a CDC (Change Data Capture) használatát. Ennek a megközelítésnek a fő hátrányai a következők:

  • Adatbázis-specifikus megoldások

  • Megnövekedett késleltetés a CDC-megvalósítások sajátosságai miatt


Egy másik módszer a Polling Publisher , amely a kimenő levelek táblázat lekérdezésével megkönnyíti a kimenő levelek kitöltését. Ennek a megközelítésnek az elsődleges hátránya a megnövekedett adatbázis-terhelés lehetősége, ami magasabb költségekhez vezethet. Ezenkívül nem minden No-SQL adatbázis támogatja az adott dokumentumszegmensek hatékony lekérdezését. A teljes dokumentumok kibontása ezért a teljesítmény romlását eredményezheti.


Itt van egy kis sorozatdiagram, amely elmagyarázza, hogyan működik.


Hallgass magadra

A Tranzakciós kimenő minta elsődleges kihívása az adatbázis ACID tulajdonságaitól való függésében rejlik. Ez egyszerű lehet a tipikus OLTP-adatbázisokban, de kihívásokat jelent a NoSQL-területen. Ennek megoldására egy lehetséges megoldás a hozzáfűzési napló (például Kafka) kihasználása közvetlenül a kérésfeldolgozás kezdeményezésétől.


A „hitelkérelem benyújtása” parancs közvetlen feldolgozása helyett azonnal elküldjük egy belső Kafka-témába, majd az „elfogadott” eredményt visszaküldjük az ügyfélnek. Mivel azonban nagy a valószínűsége annak, hogy a parancsot még feldolgozni kell, nem tudjuk azonnal tájékoztatni az ügyfelet az eredményről. Ennek az esetleges konzisztenciának a kezelésére olyan technikákat alkalmazhatunk, mint a hosszú lekérdezés, az ügyfél által kezdeményezett lekérdezés, az optimista felhasználói felület frissítése, vagy a WebSockets vagy a Server-Sent Events használata az értesítésekhez. Ez azonban teljesen külön téma, úgyhogy térjünk vissza a kezdeti témánkhoz.


Az üzenetet egy belső Kafka témában küldtük. A Hiteligénylési szolgáltatás ezután felhasználja ezt az üzenetet – ugyanazt a parancsot, amelyet az ügyféltől kapott – és megkezdi a feldolgozást. Először is végrehajt bizonyos üzleti logikát; csak miután ez a logika sikeresen végrehajtódott és az eredmények megmaradtak, új üzeneteket tesz közzé egy nyilvános Kafka-témában.


Vessünk egy pillantást a pszeudokódra.


 public async Task HandleAsync(SubmitLoanApplicationCommand command, ...) { //First, process business logic var loanApplication = await _loanApplicationService.HandleCommandAsync(command, ...); //Then, send new events to public Kafka topic producer.Send(new LoanApplicationSubmittedEvent(loanApplication.Id)); //Then, commit offset consumer.Commit(); }


Mi van, ha az üzleti logika feldolgozása meghiúsul? Aggodalomra semmi ok, mivel az ellentételezés még nem történt meg, az üzenetet újra megpróbáljuk.


Mi van, ha új események küldése Kafkának nem sikerül? Aggodalomra semmi ok, mivel az üzleti logika idempotens, nem hoz létre duplikált hitelkérelmet. Ehelyett megpróbálja újra elküldeni az üzeneteket a nyilvános Kafka-témának.


Mi van akkor, ha üzeneteket küldenek Kafkának, de az offset véglegesítés sikertelen? Nem kell aggódni, mivel az üzleti logika idempotens, nem hoz létre duplikált hitelkérelmet. Ehelyett újra üzeneteket küld a nyilvános Kafka-témának, és reméli, hogy az ellentételezési kötelezettség ezúttal sikeres lesz.


Ennek a megközelítésnek a fő hátrányai közé tartozik az új programozási stílushoz kapcsolódó bonyolultság, az esetleges konzisztencia (mivel az ügyfél nem fogja azonnal tudni az eredményt), valamint az a követelmény, hogy minden üzleti logikának idempotensnek kell lennie.

Rendezvények beszerzése

Mi az az eseménybeszerzés, és hogyan lehetne itt alkalmazni? Az eseményforrás egy szoftver-architektúra minta, amelyet a rendszer állapotának modellezésére használnak úgy, hogy az adatok minden változását megváltoztathatatlan események sorozataként rögzítik. Ezek az események tényeket vagy állapotátmeneteket jelentenek, és az igazság egyetlen forrásaként szolgálnak a rendszer jelenlegi állapotához. Technikailag tehát egy eseményforrás-rendszer bevezetésével már minden esemény megvan az EventStore-ban, és ezt az EventStore-t a fogyasztók egyetlen igazságforrásként használhatják a történtekről. Nincs szükség speciális adatbázis-megoldásra az összes változás vagy a rendelési aggályok nyomon követésére, az egyetlen probléma az olvasási oldalon van, mivel az entitás aktuális állapotának lekéréséhez az összes eseményt újra kell játszani.

Következtetés

Ebben a cikkben több megközelítést is áttekintettünk a megbízható üzenetkezelés elosztott rendszerekben történő létrehozására. Számos javaslatot érdemes figyelembe venni, amikor ilyen jellemzőkkel rendelkező rendszereket építünk

  1. Mindig fejlesztsen idempotens fogyasztókat, mivel a hálózati hiba elkerülhetetlen.
  2. Óvatosan használja a First-Local-Commit-Then-Publish funkciót a garanciális követelmények világos megértésével.
  3. Soha ne használja az Első közzététel, majd a helyi véglegesítés megközelítést, mivel ez súlyos adatellentmondásokhoz vezethet a rendszerben.
  4. Ha a meglévő adatbázis-választási döntés nagy valószínűséggel módosulhat, vagy a technikai stratégia azt jelenti, hogy a legjobb tárolási megoldást kell kiválasztani a problémára – ne építsen megosztott könyvtárakat olyan adatbázis-megoldásokhoz, mint a CDC .
  5. Használja a Tranzakciós kimenő üzeneteket standard megoldásként a legalább egyszeri garanciák eléréséhez.
  6. Fontolja meg a Figyeljen önmagára megközelítés használatát, ha az SQL- nélküli adatbázisokat kihasználja.


Legközelebb egy gyakorlatiasabb példát tekintünk meg a Tranzakciós kimenő postafiók megvalósítására. Lásd

te!