A lecke végére el tudod magyarázni a kettős írás problémáját, az outbox és az inbox szerepét, és meg tudod mondani, mit zárnak be és mit hagynak nyitva.
Miért kell?
Gyakori helyzet, hogy egy szolgáltatás adatot ment és üzenetet küld. Ha ez két külön rendszerben történik, a két lépés között a folyamat kieshet. Egy try–catch blokk nem teszi közös tranzakcióvá az adatbázist és az üzenetközvetítőt.
A kettős írás hibája
A microservices.io leírása szerint a szolgáltatásnak atomi módon kell frissítenie az adatbázist és üzenetet közzétennie, kétfázisú commit pedig általában nem áll rendelkezésre. Ha az üzenet küldése a mentés után történik, a mentés után bekövetkező kiesés miatt az esemény hiányozhat. Ha a küldés megelőzi a mentést, a fogyasztó olyan dologról értesülhet, amely nem jött létre.
Transactional outbox
A megoldás: az üzenetet ugyanabban a helyi adatbázis-tranzakcióban kell menteni, mint az üzleti adatot, egy outbox táblába (vagy gyűjteménybe). Egy külön relay (üzenetátvivő) ezután kiolvassa az outbox tartalmát, és közzéteszi a közvetítőn. A relay megvalósítható lekérdezéssel (polling publisher) vagy az adatbázis tranzakciós naplójának követésével (transaction log tailing).
sequenceDiagram
participant S as Szolgáltatás
participant D as Saját adatbázis
participant R as Relay
participant B as Közvetítő
S->>D: BEGIN
S->>D: Üzleti adat + outbox-rekord
S->>D: COMMIT
R->>D: Kiküldendő rekordok
R->>B: Üzenet közzététele
R->>D: Kiküldés rögzítése
A relay a közzététel után, de a rögzítés előtt kieshet, így ugyanaz az üzenet kétszer is kimehet. Az outbox tehát nem szünteti meg a duplikációt; a fogyasztónak idempotensnek kell lennie (6.5, 8.2). A microservices.io a hibalehetőségek közt azt is említi, hogy a fejlesztő elfelejtheti a bejegyzést megírni.
Több relay és sorrend
Több relaynek össze kell hangolnia, ki melyik rekordot veszi fel (zárolás, bérlet, partíciónkénti kiosztás), különben feleslegesen párhuzamosan dolgoznak; a kiesés után a munkát újra fel kell tudni venni. Az outbox tábla önmagában nem ad sorrendi garanciát: egy entitás két eseményét két relay fordított sorrendben is kiküldheti (8.3).
Inbox a fogadónál
Az inbox a fogadott üzenet azonosítóját tárolja. A fogyasztó az üzleti módosítással egy tranzakcióban rögzíti, hogy az üzenetet alkalmazta; egyedi kulcs védi a párhuzamos duplikáció ellen. A közvetítőnek küldött nyugta ezután következik. Így egy újrakézbesített üzenet felismerhető, és a hatás nem ismétlődik.
Külső API hívásnál az inbox és a helyi tranzakció nem képes atomi módon bevonni a távoli hatást. Ilyenkor a külső API idempotenciakulcsa, állapotlekérdezése vagy egyeztetés kell (6.5).
Működési következmények
A ki nem küldött rekordok száma és kora megfigyelendő. A hosszan várakozó esemény üzleti késést jelent. A tábla takarítása és a megőrzés mérlegelendő: a törlés ne tegye lehetetlenné a hibakeresést vagy a visszajátszást.
Gyakori tévhitek
Állítás
Pontosítás
„Az outbox pontosan egyszer küld.”
Legalább egyszer küld; duplikáció lehetséges.
„Az outbox globális sorrendet ad.”
Nem; a sorrendet külön kell kezelni.
„Az inbox megoldja a külső fizetés duplikációját.”
Külső hatásnál a külső rendszer idempotenciája is kell.
„A try–catch elég a két lépés között.”
Nem teszi közös tranzakcióvá a két rendszert.
Röviden
A kettős írás hibája: az adatmentés és az üzenetküldés két külön rendszerben nem atomi.
Az outbox az üzenetet az üzleti adattal egy helyi tranzakcióban menti; a relay később küldi ki.
Az outbox legalább egyszeri kézbesítést ad; a fogyasztónak idempotensnek kell lennie.
Az inbox a feldolgozott azonosítót az üzleti módosítással egy tranzakcióban rögzíti.
Ellenőrző kérdések
Melyik hibafolyamatot javítja az outbox, és melyiket nem?
Hol keletkezhet duplikáció a relay működésében?
Miért nem elég inboxot használni pontosan egyszeri banki terheléshez?
Transactional outbox és inbox
Célok
A lecke végére el tudod magyarázni a kettős írás problémáját, az outbox és az inbox szerepét, és meg tudod mondani, mit zárnak be és mit hagynak nyitva.
Miért kell?
Gyakori helyzet, hogy egy szolgáltatás adatot ment és üzenetet küld. Ha ez két külön rendszerben történik, a két lépés között a folyamat kieshet. Egy try–catch blokk nem teszi közös tranzakcióvá az adatbázist és az üzenetközvetítőt.
A kettős írás hibája
A microservices.io leírása szerint a szolgáltatásnak atomi módon kell frissítenie az adatbázist és üzenetet közzétennie, kétfázisú commit pedig általában nem áll rendelkezésre. Ha az üzenet küldése a mentés után történik, a mentés után bekövetkező kiesés miatt az esemény hiányozhat. Ha a küldés megelőzi a mentést, a fogyasztó olyan dologról értesülhet, amely nem jött létre.
Transactional outbox
A megoldás: az üzenetet ugyanabban a helyi adatbázis-tranzakcióban kell menteni, mint az üzleti adatot, egy outbox táblába (vagy gyűjteménybe). Egy külön relay (üzenetátvivő) ezután kiolvassa az outbox tartalmát, és közzéteszi a közvetítőn. A relay megvalósítható lekérdezéssel (polling publisher) vagy az adatbázis tranzakciós naplójának követésével (transaction log tailing).
A relay a közzététel után, de a rögzítés előtt kieshet, így ugyanaz az üzenet kétszer is kimehet. Az outbox tehát nem szünteti meg a duplikációt; a fogyasztónak idempotensnek kell lennie (6.5, 8.2). A microservices.io a hibalehetőségek közt azt is említi, hogy a fejlesztő elfelejtheti a bejegyzést megírni.
Több relay és sorrend
Több relaynek össze kell hangolnia, ki melyik rekordot veszi fel (zárolás, bérlet, partíciónkénti kiosztás), különben feleslegesen párhuzamosan dolgoznak; a kiesés után a munkát újra fel kell tudni venni. Az outbox tábla önmagában nem ad sorrendi garanciát: egy entitás két eseményét két relay fordított sorrendben is kiküldheti (8.3).
Inbox a fogadónál
Az inbox a fogadott üzenet azonosítóját tárolja. A fogyasztó az üzleti módosítással egy tranzakcióban rögzíti, hogy az üzenetet alkalmazta; egyedi kulcs védi a párhuzamos duplikáció ellen. A közvetítőnek küldött nyugta ezután következik. Így egy újrakézbesített üzenet felismerhető, és a hatás nem ismétlődik.
Külső API hívásnál az inbox és a helyi tranzakció nem képes atomi módon bevonni a távoli hatást. Ilyenkor a külső API idempotenciakulcsa, állapotlekérdezése vagy egyeztetés kell (6.5).
Működési következmények
A ki nem küldött rekordok száma és kora megfigyelendő. A hosszan várakozó esemény üzleti késést jelent. A tábla takarítása és a megőrzés mérlegelendő: a törlés ne tegye lehetetlenné a hibakeresést vagy a visszajátszást.
Gyakori tévhitek
Röviden
Ellenőrző kérdések
Források