Model Event Sourcing

Bookings

Namísto toho, abyste uchovávali jen aktuální stav dat, můžete pro záznam úplné posloupnosti akcí prováděných u dat využívat úložiště, které nabízí jen možnost připojovat. Toto úložiště funguje jako záznamový systém a je možné ho použít pro materializaci doménových objektů. To může zjednodušit úlohy ve složitých doménách díky tomu, že odpadá nutnost synchronizovat datový model a firemní doménu a současně se zvýší výkon, škálovatelnost a odezva. Může se tím také zajistit konzistence transakčních dat a je možné uchovávat úplné záznamy pro audit a historii, což umožní provádět kompenzační akce.

Kontext a problém

Většina aplikací pracuje s daty a typický přístup je, že aplikace udržuje aktuální stav dat tím, že je průběžně aktualizuje, jak je uživatelé mění. Například v tradičním modelu vytvoření, čtení, aktualizace a odstranění (CRUD) je typickým procesem dat čtení dat z úložiště, provedení některých úprav a aktualizace aktuálního stavu dat novými hodnotami – často pomocí transakcí, které data zamknou.

Metoda CRUD má určitá omezení:

  • Systémy CRUD provádějí operace aktualizace přímo v úložišti dat. Tyto operace můžou zpomalit výkon a rychlost odezvy a můžou omezit škálovatelnost kvůli režii na zpracování, které vyžaduje.

  • V doméně pro spolupráci s mnoha souběžnými uživateli je vyšší pravděpodobnost konfliktů při aktualizacích dat, protože aktualizační operace můžou probíhat u stejné datové položky.

  • Pokud neexistuje jiný mechanismus auditování, který zaznamenává podrobnosti o jednotlivých operacích v samostatném protokolu, historie se ztratí.

Řešení

Model Event Sourcing definuje metodu zpracovávání datových operací, která vychází z posloupnosti událostí – přičemž každá z nich je zaznamenána v úložišti, které nabízí jen možnost připojovat. Aplikační kód odesílá řadu událostí, které imperativně popisují každou akci, k níž u dat dojde, do úložiště událostí, kde se trvale uloží. Každá událost představuje sadu změn dat (například AddedItemToOrder).

Události se uchovávají v úložišti událostí, které funguje jako záznamový systém (autoritativní zdroj dat) aktuálního stavu dat. Úložiště událostí obvykle tyto události publikuje, aby příjemci měli potřebné informace a mohli je v případě potřeby zpracovat. Příjemci můžou například spouštět úlohy, které operace v událostech aplikují v jiných systémech nebo provedou jakoukoli související akci, která je nutná pro dokončení operace. Všimněte si, že aplikační kód, který generuje události, je oddělený od systémů, které události odebírají.

Typické použití událostí, které publikuje úložiště událostí, spočívá v udržování materializovaných zobrazení entit, jak je mění akce v aplikaci, a v jejich využití pro integraci s externími systémy. Systém například může udržovat materializované zobrazení všech objednávek zákazníků, které slouží k dosazování hodnot do částí uživatelského rozhraní. Aplikace přidá nové objednávky, přidá nebo odebere položky objednávky a přidá informace o expedici. Události, které popisují tyto změny, lze zpracovat a použít k aktualizaci materializovaného zobrazení.

V každém okamžiku je možné, aby aplikace četly historii událostí. Pak ho můžete použít k materializaci aktuálního stavu entity tím, že přehrajete a využijete všechny události, které souvisejí s danou entitou. Tento proces může nastat na vyžádání k materializaci objektu domény při zpracování požadavku. Nebo proces probíhá prostřednictvím naplánované úlohy, aby stav entity mohl být uložen jako materializované zobrazení pro podporu prezentační vrstvy.

Na obrázku vidíme schéma tohoto modelu, včetně některých možností pro použití datového proudu událostí, jako je například vytvoření materializovaného zobrazení, integrace událostí s externími aplikacemi a systémy a přehrávání událostí za účelem vytváření projekcí aktuálního stavu konkrétních entit.

Přehled a příklad modelu Event Sourcing

Model Event Sourcing má následující výhody:

  • Události jsou neměnné a je možné je uložit pomocí operace spočívající v pouhém připojení. Uživatelské rozhraní, pracovní postup nebo proces, jenž událost spustil, může pokračovat a úlohy, které zpracovávají události, můžou běžet na pozadí. Tento proces v kombinaci se skutečností, že během zpracování transakcí neexistuje kolize, může výrazně zvýšit výkon a škálovatelnost aplikací, zejména pro prezentační úroveň nebo uživatelské rozhraní.

  • Události jsou jednoduché objekty, které popisují určitou akci, ke které došlo, spolu se všemi přidruženými daty, která jsou nutná k popisu akce reprezentované událostí. Události neaktualizují úložiště dat přímo. Jednoduše se zaznamenají, aby byly zpracovány v příslušnou dobu. Použití událostí může zjednodušit implementaci a správu.

  • Expertovi na doménu budou události obvykle dávat smysl, ale neshoda v oblasti objektově-relační impedance může zhoršit srozumitelnost u složitých databázových tabulek. Tabulky jsou umělé konstrukce, které představují aktuální stav systému, nikoli události, k nimž došlo.

  • Model Event Sourcing může pomoct předcházet konfliktům vyplývajícím ze souběžných aktualizací, protože se eliminuje nutnost přímo aktualizovat objekty v úložišti dat. I přesto ale musí být model domény navržen tak, aby se chránil před žádostmi, které by mohly vést k nekonzistentnímu stavu.

  • Úložiště událostí pouze s připojením poskytuje záznam auditu, který lze použít k monitorování akcí provedených v úložišti dat. Aktuální stav může kdykoli znovu vygenerovat jako materializovaná zobrazení nebo projekce tím, že události přehraje a může pomoct s testováním a laděním systému. Kromě toho požadavek na použití kompenzačních událostí ke zrušení změn může poskytnout historii změn, které byly obráceny. Tato funkce by nebyla případem, kdy model uložil aktuální stav. Seznam událostí lze také použít k analýze výkonu aplikace a k detekci trendů chování uživatelů. Nebo se dá použít k získání dalších užitečných obchodních informací.

  • Úložiště událostí vytváří události a úlohy v reakci na tyto události provádějí operace. Toto oddělení úloh od události zajišťuje flexibilitu a rozšiřitelnost. Úlohy znají typ události a data události, ale neví o operaci, která událost spustila. Kromě toho může každou událost zpracovávat více úloh. To umožňuje snadnou integraci s dalšími službami a systémy, které naslouchají jen novým událostem vytvořeným v úložišti událostí. Ale události v modelu Event Sourcing jsou často na velmi nízké úrovni a možná bude nezbytné generovat místo nich specifické integrační události.

Model Event Sourcing se často kombinuje s modelem CQRS, takže se v reakci na události provádějí úlohy správy dat a z uložených událostí se materializují zobrazení.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

Vzhledem k vytváření materializovaných zobrazení nebo generování projekcí dat přehráváním událostí se systém vyznačuje konzistencí s prodlevou (eventual consistency). Mezi aplikací, která přidává události do úložiště událostí v důsledku zpracování požadavku, publikování událostí a příjemců událostí, které s nimi zpracovávají, dochází ke zpoždění. Během této doby se v úložišti událostí mohou objevit nové události, které popisují další změny entity. Systém by měl být navržen tak, aby v těchto scénářích zohlednil konečnou konzistenci.

Poznámka:

Informace o konzistenci s prodlevou najdete v tématu Úvod do konzistence dat.

Úložiště událostí je trvalý zdroj informací, takže data událostí by se nikdy neměla aktualizovat. Jediný způsob, jak aktualizovat entitu, aby se změna zrušila, je přidat do úložiště událostí kompenzační událost. Pokud je u trvale uložených událostí potřeba změnit formát (nikoli data), třeba při migraci, může být obtížné kombinovat existující události v úložišti s novou verzí. Možná bude nutné iterovat všechny tyto události provedením příslušných změn, aby byly kompatibilní s novým formátem, nebo přidat nové události, které používají nový formát. Zvažte použití razítka verze v každé verzi schématu událostí, aby se zachoval starý i nový formát událostí.

Do úložiště událostí můžou události ukládat vícevláknové aplikace a více instancí aplikací. Konzistence událostí v úložišti událostí je klíčová, stejně jako pořadí událostí, které se týkají konkrétní entity (pořadí, v jakém u entity ke změnám dochází, ovlivňuje její aktuální stav). Přidání časového razítka ke každé události může pomoct předcházet problémům. Dalším běžným postupem je opatřit každou událost vyplývající z žádosti přírůstkovým identifikátorem. Pokud se dvě akce současně pokusí o přidání událostí pro stejnou entitu, úložiště událostí může zamítnout událost, která odpovídá existujícímu identifikátoru entity a identifikátoru události.

Neexistuje žádná standardní metoda nebo mechanismy, jako jsou dotazy SQL, pro čtení událostí s cílem získat informace. Jediná data, která je možné extrahovat, je datový proud událostí, a to použitím identifikátoru události jako kritéria. ID události se obvykle mapuje k jednotlivým entitám. Aktuální stav entity se dá určit jedině přehráním všech událostí, které se k ní vztahují, vůči jejímu původnímu stavu.

Délka každého datového proudu událostí ovlivňuje správu a aktualizaci systému. Pokud jsou datové proudy velké, zvažte vytváření snímků v určitých intervalech, například po určitém počtu událostí. Aktuální stav entity je možné získat ze snímku a po přehrání všech událostí, které nastaly po tomto bodu v čase. Další informace o vytváření snímků dat naleznete v tématu Replikace primárních podřízených snímků.

I když Event Sourcing minimalizuje možnost konfliktních aktualizací dat, přesto musí být aplikace schopna řešit nekonzistence, které způsobuje konzistence s prodlevou (eventual consistency) a absence transakcí. Například událost, která indikuje snížení zásob zásob, může přicházet do úložiště dat, zatímco je objednávka pro danou položku umístěna. Výsledkem této situace je požadavek na odsouhlasení těchto dvou operací, a to buď doporučením zákazníka, nebo vytvořením objednávky zpět.

Publikování událostí může být alespoň jednou, takže příjemci událostí musí být idempotentní. Aktualizaci popsanou v události nesmí aplikovat opakovaně, pokud se událost zpracovává více než jednou. Více instancí příjemce může udržovat a agregovat vlastnost entity, například celkový počet zadaných objednávek. Pouze jeden musí být úspěšný při zvýšení agregace v případě, že dojde k události umístěné v objednávce. I když tento výsledek není klíčovou charakteristikou zdroje událostí, jedná se o obvyklé rozhodnutí o implementaci.

Vybrané úložiště událostí musí podporovat zatížení událostí vygenerované vaší aplikací.
Mějte na paměti scénáře, kdy zpracování jedné události zahrnuje vytvoření jedné nebo více nových událostí, protože to může způsobit nekonečnou smyčku.

Kdy se má tento model použít

Tento model se používá v následujících scénářích:

  • Pokud chcete v datech zaznamenat záměr, účel nebo důvod. Například změny entity zákazníka lze zaznamenat jako řadu konkrétních typů událostí, jako je Přesunuto domů, Uzavřený účet nebo Zůsnulý.

  • Když je důležité minimalizovat nebo zcela vyloučit výskyt konfliktních aktualizací dat.

  • Pokud chcete zaznamenávat události, ke kterým dochází, abyste je přehráli za účelem obnovení stavu systému, vrácení změn zpět nebo uchování historie a protokolu auditování. Pokud například úkol zahrnuje více kroků, budete možná muset provést akce, aby se aktualizace vrátily, a pak znovu přehrát některé kroky, aby se data vrátila do konzistentního stavu.

  • Při použití událostí. Je to přirozená funkce provozu aplikace a vyžaduje málo dalšího úsilí o vývoj nebo implementaci.

  • Pokud potřebujete oddělit proces zadávání nebo aktualizovat data od úloh potřebných k použití těchto akcí. Touto změnou může být zvýšení výkonu uživatelského rozhraní nebo distribuce událostí jiným naslouchacím procesům, které při výskytu událostí podniknou akci. Můžete například integrovat mzdový systém s webem pro odeslání výdajů. Události, které jsou vyvolány úložištěm událostí v reakci na aktualizace dat provedených na webu, by byly spotřebovány webem i systémem mzdy.

  • Pokud chcete mít flexibilitu, abyste mohli změnit formát materializovaných modelů a dat entit, pokud se změní požadavky nebo při použití s CQRS, musíte přizpůsobit model čtení nebo zobrazení, která data zveřejňují.

  • Při použití s CQRS a konečná konzistence je přijatelná, když se aktualizuje model čtení, nebo je přijatelný dopad na výkon dosazování entit a dat z datového proudu událostí.

Tento model nemusí být vhodný v následujících situacích:

  • Malé nebo jednoduché domény, systémy s minimální nebo vůbec žádnou obchodní logikou nebo jiné nedoménové systémy, které přirozeně fungují dobře s tradičními mechanismy správy dat CRUD.

  • Systémy, kde je vyžadována konzistence a aktualizace zobrazení dat v reálném čase.

  • Systémy, kde se nevyžadují záznamy auditu, historie a možnosti vrácení zpět a přehrání akcí.

  • Systémy, kde dochází pouze k nízkému výskytu konfliktních aktualizací podkladových dat. Například systémy, ve kterých se data převážně přidávají a neprovádějí se tolik jejich aktualizace.

Návrh úloh

Architekt by měl vyhodnotit způsob použití modelu Event Sourcing v návrhu úlohy k řešení cílů a principů popsaných v pilířích architektury Azure Well-Architected Framework. Příklad:

Pilíř Jak tento model podporuje cíle pilíře
Rozhodnutí o návrhu spolehlivosti pomáhají vaší úloze stát se odolnou proti selhání a zajistit, aby se po selhání obnovila do plně funkčního stavu. Kvůli zaznamenání historie změn v komplexním obchodním procesu může usnadnit obnovení stavu, pokud potřebujete obnovit úložiště stavů.

- RE:06 Dělení dat
- RE:09 Zotavení po havárii
Efektivita výkonu pomáhá vaší úloze efektivně splňovat požadavky prostřednictvím optimalizací škálování, dat a kódu. Tento model, obvykle v kombinaci s CQRS, vhodným návrhem domény a strategickým snímkováním, může zlepšit výkon úloh z důvodu atomických operací jen pro připojení a zabránění uzamčení databáze pro zápisy a čtení.

- Výkon dat PE:08

Stejně jako u jakéhokoli rozhodnutí o návrhu zvažte jakékoli kompromisy proti cílům ostatních pilířů, které by mohly být s tímto vzorem zavedeny.

Příklad

Systém řízení konferencí musí sledovat počet dokončených rezervací pro konferenci. Tímto způsobem může zkontrolovat, jestli jsou stále k dispozici místa, když se potenciální účastník pokusí provést rezervaci. Systém může celkový počet rezervací u konference uchovávat minimálně dvěma způsoby:

  • Systém může uchovávat informace o celkovém počtu rezervací jako samostatnou entitu v databázi, která obsahuje informace o rezervacích. Jak dochází k zadávání a rušení rezervací, může systém toto číslo podle potřeby zvyšovat nebo snižovat. Tato metoda je teoreticky jednoduchá, ale může způsobit problémy se škálovatelností, pokud se o rezervaci pokusí velký počet účastníků během krátké doby. Například poslední den před uzavřením období pro rezervace.

  • Systém může informace o rezervacích a zrušeních uchovávat jako události v samostatném úložišti událostí. Pak může počet volných míst vypočítat přehráním těchto událostí. Tato metoda může nabízet větší škálovatelnost vzhledem k neměnnosti událostí. Systém potřebuje jen schopnost číst data z úložiště událostí nebo do něho připojovat data. Informace o událostech představujících jednotlivé rezervace a zrušení se nikdy nemění.

Následující diagram znázorňuje, jak je možné subsystém pro rezervaci míst v systému správy konferencí implementovat na základě modelu Event Sourcing.

Zaznamenávání informací o rezervacích míst v systému pro správu konferencí založeném na modelu Event Sourcing

Posloupnost akcí pro rezervaci dvou míst je následující:

  1. Uživatelské rozhraní vydá příkaz k rezervaci míst pro dva účastníky. Příkaz je zpracován samostatnou obslužnou rutinou příkazu. Jde o logický zápis, který je oddělený od uživatelského rozhraní a zodpovídá za zpracování žádostí zadaných jako příkazy.

  2. Sestaví se agregace obsahující informace o všech rezervacích pro danou konferenci, a to provedením dotazu na události, které popisují rezervace a zrušení. Tato agregace se nazývá SeatAvailability a je obsažená v rámci modelu domény, který poskytuje metody pro dotazování a úpravy dat v agregaci.

    Některé optimalizace, které je potřeba zvážit, používají snímky (takže nemusíte dotazovat a přehrávat úplný seznam událostí pro získání aktuálního stavu agregace) a udržování kopie agregace v mezipaměti v paměti.

  3. Obslužná rutina příkazu vyvolá metodu poskytovanou modelem domény pro vytváření rezervací.

  4. Agregace SeatAvailability zaznamená událost obsahující počet míst, které byly rezervovány. Až agregace příště aplikuje události, použijí se při výpočtu, kolik volných míst zbývá, všechny rezervace.

  5. Systém připojí novou událost k seznamu událostí v úložišti událostí.

Pokud uživatel rezervaci místa zruší, systém postupuje podobným způsobem až na to, že obslužná rutina vydá příkaz, který vygeneruje událost zrušení rezervace a připojí ji k úložišti událostí.

Kromě zajištění většího rozsahu škálovatelnosti poskytuje úložiště událostí také kompletní historii nebo záznam auditu rezervací a zrušení konference. Události v úložišti události představují přesný záznam. Agregace není nutné uchovávat jiným způsobem, protože systém může události snadno přehrát a obnovit stav k libovolnému bodu v čase.

Další informace o tomto příkladu najdete v tématu Seznámení s modelem Event Sourcing.

Další kroky

Při implementaci tohoto modelu můžou být relevantní také následující modely a pokyny:

  • Model dělení zodpovědnosti příkazů a dotazů (CQRS): Zápisové úložiště, které poskytuje trvalý zdroj informací pro implementaci CQRS, často vychází z implementace modelu Event Sourcing. Popisuje, jak oddělit operace, které načítají data v aplikaci, od operací, které aktualizují data, a to s využitím samostatných rozhraní.

  • Model Materializované zobrazení. Úložiště dat používané v systému založeném na modelu Event Sourcing se obvykle nehodí k efektivnímu dotazování. Místo toho se obvykle postupuje tak, že se v pravidelných intervalech nebo při změně dat generují předem vyplněná zobrazení dat.

  • Model kompenzační transakce: Existující data v úložišti event sourcing se neaktualizují. Místo toho se přidají nové položky, které přejdou stav entit na nové hodnoty. Pokud chcete změnit změnu, použijí se kompenzační položky, protože předchozí změnu není možné vrátit zpět. Popisuje, jak vrátit akci provedenou pomocí předchozí operace.