GebeurtenisbronnenpatroonEvent Sourcing pattern

In plaats van alleen de huidige status van de gegevens in een domein op te slaan, gebruikt u een archief waaraan alleen gegevens kunnen worden toegevoegd, om de volledige reeks acties te registreren die op die gegevens wordt uitgevoerd.Instead of storing just the current state of the data in a domain, use an append-only store to record the full series of actions taken on that data. Het archief dient als het systeem van records en kan worden gebruikt voor het realiseren van de domeinobjecten.The store acts as the system of record and can be used to materialize the domain objects. Hiermee kunnen taken in complexe domeinen worden vereenvoudigd door het synchroniseren van het gegevensmodel en het bedrijfsdomein te omzeilen, terwijl de prestaties, de schaalbaarheid en de reactietijd worden verbeterd.This can simplify tasks in complex domains, by avoiding the need to synchronize the data model and the business domain, while improving performance, scalability, and responsiveness. Het kan ook consistentie voor transactiegegevens bieden en volledige audittrails en -geschiedenis handhaven die compenserende maatregelen mogelijk maken.It can also provide consistency for transactional data, and maintain full audit trails and history that can enable compensating actions.

Context en probleemContext and problem

De meeste toepassingen werken met gegevens en gewoonlijk wordt de huidige status van de gegevens onderhouden door deze bij te werken terwijl ermee wordt gewerkt.Most applications work with data, and the typical approach is for the application to maintain the current state of the data by updating it as users work with it. In het klassieke CRUD-model (Create, Read, Update, Delete -maken, lezen, bijwerken, verwijderen) worden in een typisch gegevensproces gegevens vanuit het archief gelezen en enigszins gewijzigd, en wordt de huidige status van de gegevens bijgewerkt met de nieuwe waarden, vaak door gebruik te maken van transacties die de gegevens vergrendelen.For example, in the traditional create, read, update, and delete (CRUD) model a typical data process is to read data from the store, make some modifications to it, and update the current state of the data with the new values—often by using transactions that lock the data.

De benadering met CRUD kent enkele beperkingen:The CRUD approach has some limitations:

  • CRUD-systemen voeren bijwerkbewerkingen rechtstreeks in een gegevensarchief uit. Hierdoor kunnen vanwege de vereiste overhead bij het verwerken de prestaties en het reactievermogen vertraagd en de schaalbaarheid beperkt worden.CRUD systems perform update operations directly against a data store, which can slow down performance and responsiveness, and limit scalability, due to the processing overhead it requires.

  • In een samenwerkingsdomein met talloze gelijktijdig werkende gebruikers, is de kans op conflicten bij het bijwerken van gegevens groter, omdat de bijwerkbewerkingen op één gegevensitem worden uitgevoerd.In a collaborative domain with many concurrent users, data update conflicts are more likely because the update operations take place on a single item of data.

  • Hierbij gaat de geschiedenis verloren, tenzij er een aanvullend controlemechanisme is dat de details van elke bewerking in een afzonderlijk logboek vastlegt.Unless there's an additional auditing mechanism that records the details of each operation in a separate log, history is lost.

Zie CRUD, Only When You Can Afford It voor een uitgebreide beschrijving van de beperkingen van de CRUD-aanpak.For a deeper understanding of the limits of the CRUD approach see CRUD, Only When You Can Afford It.

OplossingSolution

Het gebeurtenisbronnenpatroon definieert een benadering voor het afhandelen van bewerkingen op gegevens die op een reeks gebeurtenissen is gebaseerd. Elke gebeurtenis wordt vastgelegd in een archief waaraan alleen gegevens kunnen worden toegevoegd.The Event Sourcing pattern defines an approach to handling operations on data that's driven by a sequence of events, each of which is recorded in an append-only store. Door de toepassingscode wordt een reeks gebeurtenissen verzonden waarmee elke actie die op de gegevens in het gebeurtenisarchief is uitgevoerd (en waar ze definitief worden bewaard), dwingend worden beschreven.Application code sends a series of events that imperatively describe each action that has occurred on the data to the event store, where they're persisted. Elke gebeurtenis stelt een reeks gegevenswijzigingen voor (zoals AddedItemToOrder).Each event represents a set of changes to the data (such as AddedItemToOrder).

De gebeurtenissen worden definitief in een gebeurtenisarchief opgeslagen. Dit fungeert als het recordsysteem (de gezaghebbende gegevensbron) voor de huidige status van de gegevens.The events are persisted in an event store that acts as the system of record (the authoritative data source) about the current state of the data. Normaal gesproken worden deze gebeurtenissen gepubliceerd, zodat gebruikers op de hoogte kunnen worden gesteld en de gebeurtenissen zo nodig kunnen verwerken.The event store typically publishes these events so that consumers can be notified and can handle them if needed. Een gebruiker kan bijvoorbeeld taken initiëren die de bewerkingen in de gebeurtenissen toepassen op andere systemen, of een andere eraan gekoppelde actie uitvoeren die is vereist om de bewerking te voltooien.Consumers could, for example, initiate tasks that apply the operations in the events to other systems, or perform any other associated action that's required to complete the operation. De toepassingscode waarmee de gebeurtenissen worden gegenereerd, wordt losgekoppeld van de systemen die zich op de gebeurtenissen abonneren.Notice that the application code that generates the events is decoupled from the systems that subscribe to the events.

De door het gebeurtenisarchief gepubliceerde gebeurtenissen worden gewoonlijk gebruikt voor het onderhouden van gerealiseerde weergaven van entiteiten als ze door acties in de toepassing worden gewijzigd, en voor integratie met externe systemen.Typical uses of the events published by the event store are to maintain materialized views of entities as actions in the application change them, and for integration with external systems. Een systeem kan bijvoorbeeld een gerealiseerde weergave van alle klantorders onderhouden, die wordt gebruikt om delen van de gebruikersinterface te vullen.For example, a system can maintain a materialized view of all customer orders that's used to populate parts of the UI. Naarmate er nieuwe orders worden toegevoegd, er artikelen aan de order worden toegevoegd of eruit verwijderd, en er verzendgegevens worden toegevoegd, kunnen de gebeurtenissen die deze wijzigingen beschrijven, worden verwerkt en gebruikt om de gerealiseerde weergave bij te werken.As the application adds new orders, adds or removes items on the order, and adds shipping information, the events that describe these changes can be handled and used to update the materialized view.

Daarnaast kan de toepassing op elk moment de geschiedenis van de gebeurtenissen lezen en gebruiken om de huidige status van een entiteit te realiseren door alle gebeurtenissen die aan die entiteit zijn gerelateerd, af te spelen en te gebruiken.In addition, at any point it's possible for applications to read the history of events, and use it to materialize the current state of an entity by playing back and consuming all the events related to that entity. Dit kan op aanvraag gebeuren om een domeinobject te realiseren bij het verwerken van een aanvraag, of door middel van een geplande taak, zodat de status van de entiteit kan worden opgeslagen als een gerealiseerde weergave ter ondersteuning van de presentatielaag.This can occur on demand to materialize a domain object when handling a request, or through a scheduled task so that the state of the entity can be stored as a materialized view to support the presentation layer.

De afbeelding toont een overzicht van het patroon, waaronder enkele opties voor het gebruik van de gebeurtenisstroom, zoals het maken van een gerealiseerde weergave, het integreren van gebeurtenissen met externe toepassingen en systemen, en het opnieuw afspelen van gebeurtenissen om projecties te maken van de huidige status van bepaalde entiteiten.The figure shows an overview of the pattern, including some of the options for using the event stream such as creating a materialized view, integrating events with external applications and systems, and replaying events to create projections of the current state of specific entities.

Overzicht en voorbeeld van het gebeurtenisbronnenpatroon

Het gebeurtenisbronnenpatroon biedt de volgende voordelen:The Event Sourcing pattern provides the following advantages:

  • Gebeurtenissen zijn onveranderlijk en kunnen worden opgeslagen met een bewerking waarbij alleen gegevens kunnen worden toegevoegd.Events are immutable and can be stored using an append-only operation. De gebruikersinterface, de werkstroom of het proces dat een gebeurtenis heeft geïnitieerd, kan door blijven gaan, en taken die de gebeurtenissen verwerken kunnen op de achtergrond worden uitgevoerd.The user interface, workflow, or process that initiated an event can continue, and tasks that handle the events can run in the background. In combinatie met het feit dat er geen conflicten optreden tijdens het verwerken van transacties, kan dit de prestaties en de schaalbaarheid voor toepassingen aanzienlijk verbeteren, met name voor het presentatieniveau of de gebruikersinterface.This, combined with the fact that there's no contention during the processing of transactions, can vastly improve performance and scalability for applications, especially for the presentation level or user interface.

  • Gebeurtenissen zijn eenvoudige objecten waarmee wordt beschreven dat een bepaalde actie is opgetreden, in combinatie met eventuele gekoppelde gegevens die nodig zijn om de actie te beschrijven die door de gebeurtenis wordt vertegenwoordigd.Events are simple objects that describe some action that occurred, together with any associated data required to describe the action represented by the event. Gebeurtenissen werken een gegevensarchief niet rechtstreeks bij.Events don't directly update a data store. Ze worden op het juiste moment slechts geregistreerd voor verwerking.They're simply recorded for handling at the appropriate time. Hiermee kunnen de implementatie en het beheer worden vereenvoudigd.This can simplify implementation and management.

  • Gebeurtenissen hebben doorgaan betekenis voor een domeinexpert, terwijl vanwege objectrelationele onverenigbaarheid complexe databasetabellen soms lastig te begrijpen zijn.Events typically have meaning for a domain expert, whereas object-relational impedance mismatch can make complex database tables hard to understand. Tabellen zijn kunstmatige constructies die de huidige status van het systeem vertegenwoordigen, niet de gebeurtenissen die hebben plaatsgevonden.Tables are artificial constructs that represent the current state of the system, not the events that occurred.

  • Met gebeurtenisbronnen kan worden voorkomen dat gelijktijdige updates conflicten veroorzaken, omdat de vereiste voor het rechtstreeks bijwerken van objecten in het gegevensarchief wordt vermeden.Event sourcing can help prevent concurrent updates from causing conflicts because it avoids the requirement to directly update objects in the data store. Het domeinmodel moet echter nog steeds zodanig worden ontworpen dat aanvragen die tot een inconsistente status kunnen leiden, worden voorkomen.However, the domain model must still be designed to protect itself from requests that might result in an inconsistent state.

  • Dat gebeurtenissen worden opgeslagen in een archief waaraan alleen gegevens kunnen worden toegevoegd, biedt een audittrail die kan worden gebruikt voor het bewaken van acties die in een gegevensarchief zijn ondernomen, voor het regenereren van de huidige status als gerealiseerde weergaven of projecties door de gebeurtenissen op een willekeurig moment opnieuw af te spelen, en voor het testen van en fouten opsporen in het systeem.The append-only storage of events provides an audit trail that can be used to monitor actions taken against a data store, regenerate the current state as materialized views or projections by replaying the events at any time, and assist in testing and debugging the system. Daarnaast biedt de vereiste om compenserende gebeurtenissen te gebruiken om wijzigingen te annuleren een geschiedenis van teruggedraaide wijzigingen, wat niet het geval zou zijn als bij dit model alleen de huidige status zou worden opgeslagen.In addition, the requirement to use compensating events to cancel changes provides a history of changes that were reversed, which wouldn't be the case if the model simply stored the current state. De lijst met gebeurtenissen kan ook worden gebruikt voor het analyseren van de prestaties van toepassingen en het detecteren van trends in gebruikersgedrag, of om andere nuttige bedrijfsinformatie te verkrijgen.The list of events can also be used to analyze application performance and detect user behavior trends, or to obtain other useful business information.

  • Het gebeurtenissenarchief activeert gebeurtenissen en taken voeren bewerkingen uit als reactie op die gebeurtenissen.The event store raises events, and tasks perform operations in response to those events. Deze ontkoppeling van de taken van de gebeurtenissen biedt flexibiliteit en uitbreidbaarheid.This decoupling of the tasks from the events provides flexibility and extensibility. De taken kennen het type en de datum van de gebeurtenis, maar niet de bewerking die de gebeurtenis heeft geactiveerd.Tasks know about the type of event and the event data, but not about the operation that triggered the event. Bovendien kan elke gebeurtenis door meerdere taken worden verwerkt.In addition, multiple tasks can handle each event. Hierdoor is eenvoudige integratie mogelijk met andere services en systemen die alleen letten op nieuwe gebeurtenissen die door het gebeurtenissenarchief worden geactiveerd.This enables easy integration with other services and systems that only listen for new events raised by the event store. De gebeurtenissen met betrekking tot gebeurtenisbronnen zijn meestal van een erg laag niveau. Het kan daarom noodzakelijk zijn in plaats daarvan specifieke integratiegebeurtenissen te genereren.However, the event sourcing events tend to be very low level, and it might be necessary to generate specific integration events instead.

Gebeurtenisbronnen worden gewoonlijk gecombineerd met het CQRS-patroon door gegevensbeheertaken uit te voeren als reactie op de gebeurtenissen, en door weergaven vanuit de opgeslagen gebeurtenissen te realiseren.Event sourcing is commonly combined with the CQRS pattern by performing the data management tasks in response to the events, and by materializing views from the stored events.

Problemen en overwegingenIssues and considerations

Beschouw de volgende punten als u besluit hoe u dit patroon wilt implementeren:Consider the following points when deciding how to implement this pattern:

Het systeem is uiteindelijk pas consistent als er gerealiseerde weergaven worden gemaakt of projecties van gegevens gegenereerd door gebeurtenissen opnieuw af te spelen.The system will only be eventually consistent when creating materialized views or generating projections of data by replaying events. Er is enige vertraging tussen het toevoegen van gebeurtenissen aan het gebeurtenissenarchief als gevolg van het verwerken van een aanvraag, het publiceren van de gebeurtenissen en het verwerken ervan door gebruikers.There's some delay between an application adding events to the event store as the result of handling a request, the events being published, and consumers of the events handling them. Tijdens deze periode kunnen gebeurtenissen waarin verdere wijzigingen aan entiteiten worden beschreven, in het gebeurtenissenarchief zijn binnengekomen.During this period, new events that describe further changes to entities might have arrived at the event store.

Notitie

Zie Data Consistency Primer (Inleiding tot gegevensconsistentie) voor informatie over uiteindelijke consistentie.See the Data Consistency Primer for information about eventual consistency.

Het gebeurtenissenarchief is de permanente informatiebron. De gebeurtenisgegevens mogen dan ook nooit worden bijgewerkt.The event store is the permanent source of information, and so the event data should never be updated. De enige manier om een entiteit bij te werken om een wijziging ongedaan te maken, is door een compenserende gebeurtenis aan het gebeurtenissenarchief toe te voegen.The only way to update an entity to undo a change is to add a compensating event to the event store. Als de indeling (niet de gegevens) van de persistente gebeurtenissen moeten worden gewijzigd (bijvoorbeeld tijdens een migratie), kan het lastig zijn bestaande gebeurtenissen in het archief te combineren met de nieuwe versie.If the format (rather than the data) of the persisted events needs to change, perhaps during a migration, it can be difficult to combine existing events in the store with the new version. Mogelijk dienen alle gebeurtenissen die wijzigingen aanbrengen, doorlopen te worden, zodat ze aan de nieuwe indeling voldoen. Of er dienen nieuwe gebeurtenissen te worden toegevoegd die de nieuwe indeling gebruiken.It might be necessary to iterate through all the events making changes so they're compliant with the new format, or add new events that use the new format. U kunt bijvoorbeeld een versiestempel gebruiken op elke versie van het gebeurtenissenschema, zodat zowel de oude als de nieuwe indeling behouden blijft.Consider using a version stamp on each version of the event schema to maintain both the old and the new event formats.

Mogelijk kunnen zowel toepassingen met meerdere threads als meerdere exemplaren van toepassingen gebeurtenissen in het gebeurtenissenarchief opslaan.Multi-threaded applications and multiple instances of applications might be storing events in the event store. De consistentie van gebeurtenissen in het gebeurtenissenarchief is van vitaal belang, evenals de volgorde van gebeurtenissen die van invloed is op een bepaalde entiteit (de volgorde waarin wijzigingen aan een entiteit optreden, beïnvloedt de huidige status ervan).The consistency of events in the event store is vital, as is the order of events that affect a specific entity (the order that changes occur to an entity affects its current state). Door een tijdstempel aan elke gebeurtenis toe te voegen kunnen problemen worden voorkomen.Adding a timestamp to every event can help to avoid issues. Een andere veelgebruikte methode bestaat uit het toevoegen van aantekeningen aan elke gebeurtenis die het gevolg zijn van een aanvraag met een incrementele id.Another common practice is to annotate each event resulting from a request with an incremental identifier. Als twee acties tegelijkertijd gebeurtenissen voor dezelfde entiteit willen toevoegen, kan het gebeurtenissenarchief een gebeurtenis weigeren die overeenkomt met een bestaande entiteit-id en gebeurtenis-id.If two actions attempt to add events for the same entity at the same time, the event store can reject an event that matches an existing entity identifier and event identifier.

Er bestaan geen standaardmethoden of al aanwezige mechanismen (zoals SQL-query's) om gebeurtenissen te lezen om informatie te verkrijgen.There's no standard approach, or existing mechanisms such as SQL queries, for reading the events to obtain information. De enige gegevens die kunnen worden geëxtraheerd zijn een stroom gebeurtenissen die een gebeurtenis-id als criteria gebruiken.The only data that can be extracted is a stream of events using an event identifier as the criteria. De gebeurtenis-id is doorgaans toegewezen aan afzonderlijke entiteiten.The event ID typically maps to individual entities. De huidige status van een entiteit kan alleen worden bepaald door alle gebeurtenissen die er betrekking op hebben, opnieuw af te spelen tegen de oorspronkelijke status van die entiteit.The current state of an entity can be determined only by replaying all of the events that relate to it against the original state of that entity.

De lengte van elke gebeurtenisstroom is van invloed op het beheren en bijwerken van het systeem.The length of each event stream affects managing and updating the system. Als de stromen groot zijn, kunt u op bepaalde tijdstippen momentopnamen maken, bijvoorbeeld van een bepaald aantal gebeurtenissen.If the streams are large, consider creating snapshots at specific intervals such as a specified number of events. De huidige status van de entiteit kan uit de momentopname worden verkregen en door alle gebeurtenissen die na dat tijdstip zijn opgetreden, opnieuw af te spelen.The current state of the entity can be obtained from the snapshot and by replaying any events that occurred after that point in time. Zie Snapshot op de website Enterprise Application Architecture van Martin Fowler (Engelstalig) en Master-Subordinate Snapshot Replication (Replicatie van hoofd- en onderliggende momentopnamen) voor meer informatie over het maken van momentopnamen van gegevens.For more information about creating snapshots of data, see Snapshot on Martin Fowler’s Enterprise Application Architecture website and Master-Subordinate Snapshot Replication.

Hoewel met gebeurtenisbronnen de kans op conflicterende updates van gegevens wordt geminimaliseerd, moet de toepassing nog steeds in staat zijn inconsistenties af te kunnen handelen die het gevolg zijn van uiteindelijke inconsistentie en het gebrek aan transacties.Even though event sourcing minimizes the chance of conflicting updates to the data, the application must still be able to deal with inconsistencies that result from eventual consistency and the lack of transactions. Een gebeurtenis die bijvoorbeeld een afname van de voorraad van een bepaald artikel aangeeft, kan in het gegevensarchief terechtkomen terwijl er een order voor dat artikel wordt geplaatst. Dit leidt ertoe dat de twee bewerkingen met elkaar in overeenstemming moeten worden gebracht door ofwel de klant te adviseren of door een nabestelling te maken.For example, an event that indicates a reduction in stock inventory might arrive in the data store while an order for that item is being placed, resulting in a requirement to reconcile the two operations either by advising the customer or creating a back order.

Publicatie van gebeurtenissen kan 'ten minste eenmaal' plaatsvinden, dus de gebruikers van de gebeurtenissen moeten idempotent zijn.Event publication might be “at least once,” and so consumers of the events must be idempotent. Zij moeten de update die in een gebeurtenis staat beschreven, niet opnieuw toepassen als de gebeurtenis vaker wordt verwerkt.They must not reapply the update described in an event if the event is handled more than once. Als bijvoorbeeld meerdere exemplaren van een gebruiker een aggregatie van de eigenschap van een entiteit (bijvoorbeeld het totale aantal geplaatste orders) onderhouden, dient er slechts een de aggregatie te verhogen als de gebeurtenis Order geplaatst optreedt.For example, if multiple instances of a consumer maintain an aggregate an entity's property, such as the total number of orders placed, only one must succeed in incrementing the aggregate when an order placed event occurs. Hoewel dit geen belangrijk kenmerk van gebeurtenisbronnen is, is dit het gebruikelijke implementatiebesluit.While this isn't a key characteristic of event sourcing, it's the usual implementation decision.

Wanneer dit patroon gebruikenWhen to use this pattern

Gebruik dit patroon in de volgende scenario's:Use this pattern in the following scenarios:

  • Als u de bedoeling, het doel of de reden in de gegevens wilt vastleggen.When you want to capture intent, purpose, or reason in the data. Bijvoorbeeld: wijzigingen aan een klantentiteit kunnen worden vastgelegd als een reeks specifieke gebeurtenistypen, zoals Verhuis, Account gesloten of Overleden.For example, changes to a customer entity can be captured as a series of specific event types such as Moved home, Closed account, or Deceased.

  • Als het cruciaal is het optreden van conflicterende updates aan gegevens te minimaliseren of volledige te voorkomen.When it's vital to minimize or completely avoid the occurrence of conflicting updates to data.

  • Als u optredende gebeurtenissen wilt registreren en ze opnieuw wilt kunnen afspelen om de status van het systeem te herstellen, wijzigingen terugdraaien of een geschiedenis en auditlogboek bijhouden.When you want to record events that occur, and be able to replay them to restore the state of a system, roll back changes, or keep a history and audit log. Als bijvoorbeeld voor een taak meerdere stappen nodig zijn, moet u wellicht acties uitvoeren om updates terug te draaien en vervolgens enkele stappen opnieuw af te spelen zodat de gegevens in een consistente status kunnen worden teruggebracht.For example, when a task involves multiple steps you might need to execute actions to revert updates and then replay some steps to bring the data back into a consistent state.

  • Als het gebruik van gebeurtenissen een natuurlijke functie van de werking van de toepassing is en hiervoor weinig aanvullende ontwikkeling of implementatie is vereist.When using events is a natural feature of the operation of the application, and requires little additional development or implementation effort.

  • Als u het proces voor het invoeren en bijwerken van gegevens wilt ontkoppelen van de taak die is vereist om deze acties toe te passen.When you need to decouple the process of inputting or updating data from the tasks required to apply these actions. Dit kan om de prestaties van de gebruikersinterface te verbeteren of om gebeurtenissen te distribueren naar andere listeners die actie ondernemen als de gebeurtenissen plaatsvinden.This might be to improve UI performance, or to distribute events to other listeners that take action when the events occur. Bijvoorbeeld: het integreren van een salarissysteem met een website waarin onkosten kunnen worden ingediend zodat gebeurtenissen die door het gebeurtenissenarchief worden geactiveerd als reactie op updates aan gegevens op de website, worden gebruikt door zowel de website als het salarissysteem.For example, integrating a payroll system with an expense submission website so that events raised by the event store in response to data updates made in the website are consumed by both the website and the payroll system.

  • Als u bij veranderende vereisten flexibel genoeg wilt zijn om de indeling te kunnen wijzigen van gerealiseerde modellen en entiteitsgegevens of (indien gebruikt in combinatie met CQRS) als u een leesmodel of de weergaven waarop de gegevens zichtbaar zijn, moet aanpassen.When you want flexibility to be able to change the format of materialized models and entity data if requirements change, or—when used in conjunction with CQRS—you need to adapt a read model or the views that expose the data.

  • Bij gebruik in combinatie met CQRS en uiteindelijke consistentie acceptabel is terwijl een leesmodel wordt bijgewerkt, of als de invloed van de prestaties bij het reactiveren van entiteiten en gegevens van een gebeurtenissenstroom acceptabel is.When used in conjunction with CQRS, and eventual consistency is acceptable while a read model is updated, or the performance impact of rehydrating entities and data from an event stream is acceptable.

Dit patroon is wellicht niet geschikt in de volgende situaties:This pattern might not be useful in the following situations:

  • Kleine of eenvoudige domeinen, systemen met weinig of geen bedrijfslogica of niet-domeinsystemen die in het algemeen goed werken met traditionele CRUD-gegevensbeheermechanismen.Small or simple domains, systems that have little or no business logic, or nondomain systems that naturally work well with traditional CRUD data management mechanisms.

  • Systemen waarbij consistentie en updates aan de weergaven van de gegevens in realtime zijn vereist.Systems where consistency and real-time updates to the views of the data are required.

  • Systemen waarbij audittrails, geschiedenis, de mogelijkheid tot terugdraaien en afspeelacties niet zijn vereist.Systems where audit trails, history, and capabilities to roll back and replay actions are not required.

  • Systemen waarbij er een zeer kleine kans is op conflicterende updates voor de onderliggende gegevens.Systems where there's only a very low occurrence of conflicting updates to the underlying data. Bijvoorbeeld systemen die hoofdzakelijk gegevens toevoegen in plaats van ze bij te werken.For example, systems that predominantly add data rather than updating it.

VoorbeeldExample

Een beheersysteem voor conferenties moet het aantal voltooide reserveringen voor een conferentie bijhouden, zodat kan worden gecontroleerd of er nog plaatsen beschikbaar zijn als een potentiële deelnemer een reservering wil maken.A conference management system needs to track the number of completed bookings for a conference so that it can check whether there are seats still available when a potential attendee tries to make a booking. Het systeem kan het totale aantal reserveringen voor een conferentie op ten minste twee manieren opslaan:The system could store the total number of bookings for a conference in at least two ways:

  • Het systeem kan informatie over het totale aantal reserveringen opslaan als een aparte entiteit in een database waarin de reserveringsgegevens worden bewaard.The system could store the information about the total number of bookings as a separate entity in a database that holds booking information. Als er reserveringen worden gedaan of geannuleerd, kan dit aantal worden verhoogd respectievelijk verlaagd.As bookings are made or canceled, the system could increment or decrement this number as appropriate. Deze benadering is in theorie eenvoudig, maar kan aanleiding geven tot schaalbaarheidsproblemen als een groot aantal deelnemers in korte tijd plaatsen wil reserveren.This approach is simple in theory, but can cause scalability issues if a large number of attendees are attempting to book seats during a short period of time. Bijvoorbeeld op de laatste dag voordat de reserveringsperiode afloopt.For example, in the last day or so prior to the booking period closing.

  • Het systeem kan informatie over reserveringen en annuleringen opslaan als gebeurtenissen die in een gebeurtenissenarchief worden bewaard.The system could store information about bookings and cancellations as events held in an event store. Vervolgens kan het aantal beschikbare plaatsen worden berekend door de gebeurtenissen opnieuw af te spelen.It could then calculate the number of seats available by replaying these events. Deze benadering kan meer schaalbaar zijn vanwege de onveranderlijkheid van de gebeurtenissen.This approach can be more scalable due to the immutability of events. Het systeem hoeft alleen maar gegevens te lezen in het gebeurtenissenarchief of gegevens toe te voegen aan het gebeurtenissenarchief.The system only needs to be able to read data from the event store, or append data to the event store. Gebeurtenisinformatie over reserveringen en annuleringen wordt nooit gewijzigd.Event information about bookings and cancellations is never modified.

In het volgende diagram wordt getoond hoe het subsysteem voor het reserveren van plaatsen van het conferentiebeheersysteem kan worden geïmplementeerd door middel van gebeurtenisbronnen.The following diagram illustrates how the seat reservation subsystem of the conference management system might be implemented using event sourcing.

Gebeurtenisbronnen gebruiken om informatie vast te leggen over plaatsreserveringen in een conferentiebeheersysteem

De volgorde van de acties voor het reserveren van twee plaatsen is als volgt:The sequence of actions for reserving two seats is as follows:

  1. De gebruikersinterface geeft de opdracht plaatsen te reserveren voor twee deelnemers.The user interface issues a command to reserve seats for two attendees. De opdracht wordt afgehandeld door een aparte opdrachthandler.The command is handled by a separate command handler. Dit is een stukje logica dat wordt ontkoppeld van de gebruikersinterface en verantwoordelijk is voor het afhandelen van aanvragen die als opdrachten zijn gepost.A piece of logic that is decoupled from the user interface and is responsible for handling requests posted as commands.

  2. Er wordt een aggregatie met informatie over alle reserveringen voor de conferentie gebouwd door query's uit te voeren in de gebeurtenissen waarin de reserveringen en annuleringen staan beschreven.An aggregate containing information about all reservations for the conference is constructed by querying the events that describe bookings and cancellations. Dit aggregaat wordt SeatAvailability genoemd en bevindt zich in een domeinmodel dat methoden beschikbaar maakt voor het uitvoeren van query's in gegevens en het wijzigen van gegevens in het aggregaat.This aggregate is called SeatAvailability, and is contained within a domain model that exposes methods for querying and modifying the data in the aggregate.

    Overweeg de volgende optimaliseringen: momentopnamen (zodat u geen query's hoeft uit te voeren en de volledige lijst met gebeurtenissen hoeft af te spelen om de huidige status van het aggregaat te verkrijgen) en een kopie van het aggregaat in de cache in-memory onderhouden.Some optimizations to consider are using snapshots (so that you don’t need to query and replay the full list of events to obtain the current state of the aggregate), and maintaining a cached copy of the aggregate in memory.

  3. De opdrachthandler roept een methode aan die door het domeinmodel beschikbaar wordt gemaakt om reserveringen te maken.The command handler invokes a method exposed by the domain model to make the reservations.

  4. Het SeatAvailability-aggregaat registreert een gebeurtenis met het aantal gereserveerde plaatsen.The SeatAvailability aggregate records an event containing the number of seats that were reserved. De volgende keer dat het aggregaat gebeurtenissen toepast, worden alle reserveringen gebruikt om te berekenen hoeveel plaatsen er nog resteren.The next time the aggregate applies events, all the reservations will be used to compute how many seats remain.

  5. Het systeem voegt de nieuwe gebeurtenis toe aan de lijst met gebeurtenissen in het gebeurtenissenarchief.The system appends the new event to the list of events in the event store.

Als een gebruiker een plaats annuleert, volgt het systeem een soortgelijk proces. Hierbij wordt een opdracht gegeven waarmee een annuleringsgebeurtenis wordt gegenereerd die aan het gebeurtenissenarchief wordt toegevoegd.If a user cancels a seat, the system follows a similar process except the command handler issues a command that generates a seat cancellation event and appends it to the event store.

Het gebruik van een gebeurtenissenarchief biedt niet alleen meer ruimte voor schaalbaarheid, maar tevens een volledige geschiedenis, of audittrail, van de reserveringen en annuleringen voor een conferentie.As well as providing more scope for scalability, using an event store also provides a complete history, or audit trail, of the bookings and cancellations for a conference. De gebeurtenissen in het gebeurtenissenarchief zijn vormen de juiste record.The events in the event store are the accurate record. Aggregaten hoeven niet definitief op een andere manier te worden opgeslagen, omdat het systeem de gebeurtenissen eenvoudig opnieuw kan afspelen en de status naar elk tijdstip kan terugzetten.There is no need to persist aggregates in any other way because the system can easily replay the events and restore the state to any point in time.

In Introducing Event Sourcing (Inleiding tot gebeurtenisbronnen) vindt u meer informatie over dit voorbeeld.You can find more information about this example in Introducing Event Sourcing.

De volgende patronen en richtlijnen zijn mogelijk ook relevant bij de implementatie van dit patroon:The following patterns and guidance might also be relevant when implementing this pattern:

  • CQRS-patroon (Command and Query Responsibility Segregation).Command and Query Responsibility Segregation (CQRS) Pattern. Het leesarchief (de permanente bron van informatie voor een CQRS-implementatie) wordt vaak gebaseerd op een implementatie van het gebeurtenisbronnenpatroon.The write store that provides the permanent source of information for a CQRS implementation is often based on an implementation of the Event Sourcing pattern. Het beschrijft hoe de bewerkingen die gegevens in een toepassing lezen, door middel van afzonderlijke interfaces moeten worden gescheiden van de bewerkingen die gegevens bijwerken.Describes how to segregate the operations that read data in an application from the operations that update data by using separate interfaces.

  • Gerealiseerde weergave-patroon.Materialized View Pattern. Het gegevensarchief dat wordt gebruikt in een systeem dat is gebaseerd op gebeurtenisbronnen, is gewoonlijk niet geschikt voor het efficiënt uitvoeren van query's.The data store used in a system based on event sourcing is typically not well suited to efficient querying. Daarom worden vaak weergaven van de gegevens gegenereerd die vooraf zijn ingevuld. Dit kan op regelmatige basis zijn of als de gegevens worden gewijzigd.Instead, a common approach is to generate prepopulated views of the data at regular intervals, or when the data changes. Toont hoe dit kan worden uitgevoerd.Shows how this can be done.

  • Compensating Transaction Pattern (Patroon Compenserende transactie).Compensating Transaction Pattern. De bestaande gegevens in een gebeurtenisbronnenarchief worden niet bijgewerkt. In plaats daarvan worden nieuwe vermeldingen toegevoegd die de status van entiteiten naar nieuwe waarden overdragen.The existing data in an event sourcing store is not updated, instead new entries are added that transition the state of entities to the new values. Voor het terugdraaien van een wijziging, wordt gebruikgemaakt van compenserende vermeldingen, omdat het niet mogelijk is de vorige wijziging eenvoudig terug te draaien.To reverse a change, compensating entries are used because it isn't possible to simply reverse the previous change. Beschrijft hoe het werk dat door een eerdere bewerking is uitgevoerd, ongedaan kan worden gemaakt.Describes how to undo the work that was performed by a previous operation.

  • Inleiding over gegevensconsistentie.Data Consistency Primer. Bij het gebruik van gebeurtenisbronnen met een afzonderlijk leesarchief of gerealiseerde weergaven, zijn de leesgegevens niet onmiddellijk consistent, maar slechts uiteindelijk consistent.When using event sourcing with a separate read store or materialized views, the read data won't be immediately consistent, instead it'll be only eventually consistent. Vat de problemen samen rond het handhaven van consistentie bij gedistribueerde gegevens.Summarizes the issues surrounding maintaining consistency over distributed data.

  • Richtlijnen voor gegevenspartitionering.Data Partitioning Guidance. Gegevens worden vaak gepartitioneerd als u gebeurtenisbronnen gebruikt om de schaalbaarheid te verbeteren, conflicten te verminderen en de prestaties te optimaliseren.Data is often partitioned when using event sourcing to improve scalability, reduce contention, and optimize performance. Beschrijft hoe gegevens in discrete partities moeten worden verdeeld en de problemen die kunnen optreden.Describes how to divide data into discrete partitions, and the issues that can arise.

  • De post Why use Event Sourcing? (Het waarom van gebeurtenisbronnen) van Greg Young.Greg Young’s post Why use Event Sourcing?.