Utiliser un SGBDR comme stockage de l’événement

Si j’utilisais un SGBDR (par exemple, SQL Server) pour stocker les données de détermination des événements, à quoi pourrait ressembler le schéma?

J’ai vu quelques variations dont on parlait dans un sens abstrait, mais rien de concret.

Par exemple, disons que l’on a une entité “Produit” et que les modifications apscopes à ce produit peuvent prendre la forme de: Prix, Coût et Description. Je suis confus quant à savoir si je:

  1. Avoir une table “ProductEvent”, qui contient tous les champs pour un produit, où chaque modification signifie un nouvel enregistrement dans cette table, plus “qui, quoi, où, pourquoi, quand et comment” selon le cas. Lorsque le coût, le prix ou la description sont modifiés, une nouvelle ligne complète est ajoutée pour représenter le produit.
  2. Stocker le coût, le prix et la description du produit dans des tables distinctes jointes à la table Produit avec une relation de clé étrangère. Lorsque des modifications sont apscopes à ces propriétés, écrivez les nouvelles lignes avec WWWWWH, le cas échéant.
  3. Stockez WWWWWH, plus un object sérialisé représentant l’événement, dans une table “ProductEvent”, ce qui signifie que l’événement lui-même doit être chargé, désérialisé et relu dans mon code d’application afin de reconstruire l’état de l’application pour un produit donné .

En particulier, je m’inquiète de l’option 2 ci-dessus. À l’extrême, la table de produit serait presque une table par propriété, où le chargement de l’état d’application pour un produit donné nécessiterait de charger tous les événements pour ce produit à partir de chaque table d’événements de produit. Cette explosion de table sent mauvais pour moi.

Je suis sûr que “ça dépend”, et bien qu’il n’y ait pas de “réponse correcte”, j’essaie de comprendre ce qui est acceptable et ce qui est totalement inacceptable. Je suis également conscient que NoSQL peut aider ici, où les événements peuvent être stockés sur une racine agrégée, ce qui signifie seulement une seule requête à la firebase database pour obtenir les événements pour reconstruire l’object, mais nous n’utilisons pas une firebase database NoSQL au moment alors je me sens autour des alternatives.

Le magasin d’événements n’a pas besoin de connaître les champs ou propriétés spécifiques des événements. Sinon, chaque modification de votre modèle entraînerait la migration de votre firebase database (comme dans le cas d’une persistance basée sur un état ancien). Je ne recommanderais donc pas les options 1 et 2 du tout.

Voici le schéma utilisé dans Ncqrs . Comme vous pouvez le constater, la table “Events” stocke les données associées sous forme de CLOB (JSON ou XML). Cela correspond à votre option 3 (Seulement qu’il n’ya pas de table “ProductEvents” car vous n’avez besoin que d’une seule table “Events” générique. Racine d’agrégat.)

Table Events: Id [uniqueidentifier] NOT NULL, TimeStamp [datetime] NOT NULL, Name [varchar](max) NOT NULL, Version [varchar](max) NOT NULL, EventSourceId [uniqueidentifier] NOT NULL, Sequence [bigint], Data [nvarchar](max) NOT NULL Table EventSources: Id [uniqueidentifier] NOT NULL, Type [nvarchar](255) NOT NULL, Version [int] NOT NULL 

Le mécanisme de persistance SQL de l’implémentation du magasin d’événements de Jonathan Oliver consiste essentiellement en une table appelée “Commits” avec un champ BLOB “Payload”. C’est à peu près la même chose que dans Ncqrs, mais il sérialise les propriétés de l’événement au format binary (ce qui, par exemple, ajoute un support de chiffrement).

Greg Young recommande une approche similaire, largement documentée sur le site Web de Greg .

Le schéma de sa table prototypique “Events” indique:

 Table Events AggregateId [Guid], Data [Blob], SequenceNumber [Long], Version [Int] 

Le projet GitHub CQRS.NET contient quelques exemples concrets de la façon dont vous pouvez faire des EventStores dans différentes technologies. Au moment de l’écriture, il existe une implémentation en SQL utilisant Linq2SQL et un schéma SQL , il y en a un pour MongoDB , un pour DocumentDB (CosmosDB si vous êtes dans Azure) et un autre utilisant EventStore (comme mentionné ci-dessus). Il y a plus dans Azure comme le stockage de table et le stockage Blob qui est très similaire au stockage de fichiers plats.

Je suppose que le point principal ici est qu’ils sont tous conformes au même principe / contrat. Ils stockent tous des informations dans un seul lieu / conteneur / tableau, ils utilisent des métadonnées pour identifier un événement d’un autre et stockent simplement l’événement dans son intégralité, tel qu’il était – dans certains cas, sérialisé, dans les technologies de support. Donc, selon que vous choisissez une firebase database de documents, une firebase database relationnelle ou même un fichier plat, il existe plusieurs manières différentes d’atteindre le même objective d’un magasin d’événements (utile si vous changez d’avis et que vous devez migrer ou prendre en charge) plus d’une technologie de stockage).

En tant que développeur du projet, je peux partager quelques idées sur certains des choix que nous avons faits.

Tout d’abord, nous avons trouvé (même avec des UUID / GUID uniques au lieu d’entiers) des identifiants séquentiels pour des raisons stratégiques, ce qui signifie que le simple fait d’avoir un ID n’était pas unique pour une clé. type d’object pour créer ce qui devrait être une clé unique (au sens de votre application). Je sais que certaines personnes disent que vous n’avez pas besoin de le stocker, mais cela dépendra de votre capacité ou de votre coexistence avec les systèmes existants.

Nous sums restés avec un seul conteneur / table / collection pour des raisons de maintenabilité, mais nous avons joué avec une table distincte par entité / object. Dans la pratique, nous avons trouvé que l’application nécessitait des permissions “CREATE” (ce qui en général n’est pas une bonne idée … généralement, il y a toujours des exceptions / exclusions) ou chaque fois qu’une nouvelle entité / object les conteneurs / tables / collections de stockage devaient être faits. Nous avons constaté que cela était extrêmement lent pour le développement local et problématique pour les déploiements de production. Vous mai pas, mais c’était notre expérience du monde réel.

Une autre chose à retenir est que demander à l’action X de se produire peut entraîner de nombreux événements différents, connaissant ainsi tous les événements générés par une commande / un événement / ce qui est utile. Ils peuvent également concerner différents types d’object, par exemple en poussant l’achat dans un panier d’achat pour déclencher des événements de compte et d’entreposage. Une application consommasortingce peut vouloir tout savoir, nous avons donc ajouté un ID de corrélation. Cela signifiait qu’un consommateur pouvait demander tous les événements liés à sa demande. Vous verrez cela dans le schéma .

Spécifiquement avec SQL, nous avons constaté que les performances devenaient vraiment un goulot d’étranglement si les index et les partitions n’étaient pas utilisés de manière adéquate. Si vous utilisez des instantanés, n’oubliez pas que les événements devront être diffusés dans l’ordre inverse. Nous avons essayé quelques index différents et constaté que, dans la pratique, des index supplémentaires étaient nécessaires pour déboguer des applications réelles en production. Encore une fois, vous verrez cela dans le schéma .

D’autres métadonnées en cours de production ont été utiles lors des enquêtes basées sur la production, les horodatages nous ont donné un aperçu de l’ordre dans lequel les événements ont persisté par rapport aux événements. Cela nous a apporté une aide sur un système particulièrement axé sur les événements, qui a généré de nombreuses quantités d’événements, nous donnant des informations sur les performances des réseaux et de la dissortingbution des systèmes sur le réseau.

Vous voudrez peut-être jeter un coup d’œil à Datomic.

Datomic est une firebase database de faits flexibles basés sur le temps , de requêtes et de jointures prenant en charge l’évolutivité élastique et les transactions ACID.

J’ai écrit une réponse détaillée ici

Vous pouvez regarder une conférence de Stuart Halloway expliquant la conception de Datomic ici

Étant donné que Datomic stocke les faits dans le temps, vous pouvez les utiliser pour les cas d’utilisation de la génération d’événements, et bien plus encore.

Un conseil possible est que le design suivi de “Slowly Changing Dimension” (type = 2) devrait vous aider à couvrir:

  • ordre des événements se produisant (via la clé de substitution)
  • durabilité de chaque état (valide à partir de – valide pour)

La fonction de pliage à gauche devrait également être correcte à implémenter, mais vous devez penser à la complexité future des requêtes.