La recherche d'événements n'est-elle valable que lorsque les écritures sont rares?

9

Je suis en train de lire sur la recherche d'événements et je ne peux pas m'empêcher de me demander si cela n'a de sens que dans des situations exotiques où les écritures sont très rares ou si un audit de niveau militaire est requis.

Un système non exceptionnel avec une utilisation importante pourrait produire entre des centaines et des milliers d'écritures par jour, se traduisant par exemple par un million ou 2 écritures (donc des événements) par année de fonctionnement. La fusion de millions d'objets (événements) juste pour obtenir l'état actuel sonne comme une proposition ridicule, par rapport à une lecture directe à partir d'un stockage traditionnel. Pourtant, le sourcing d'événements est à l'origine de certains des systèmes les plus performants (pensez LMAX).

Alors, qu'est-ce qui me manque? La restauration de l'état à partir du flux d'événements est-elle même couramment effectuée? Ou est-ce l'idée de devoir rarement le faire et d'utiliser à la place un stockage différent pour les opérations normales (c'est-à-dire utiliser le stockage de requête de CQRS), et de restaurer à partir d'événements uniquement dans des cas exceptionnels (comme la réplication, l'audit, etc.)?

kaqqao
la source

Réponses:

6

Alors, qu'est-ce qui me manque?

Faire une supposition.

La première chose qui vous manque peut-être est que vous n'avez qu'à recharger les événements pour l'état que vous reconstruisez. Si vous pouvez modéliser correctement vos limites de transaction, chaque objet peut écrire des événements étiquetés avec son propre identifiant, puis relire uniquement ces événements. En utilisant une base de données relationnelle pour le stockage des événements, il y aurait une colonne id indexée pour accélérer cette requête. En utilisant EventStore, chaque objet aurait son propre flux.

Cela prend un certain soin dans votre modèle pour le faire proprement, car vous voulez être sûr que vous ne modifiez qu'un seul objet dans chaque transaction, et donc vous devez faire attention à isoler correctement chaque invariant que vous essayez de imposer.

Dans les cas où cela n'est pas assez rapide, vous avez toujours la possibilité de créer des instantanés de votre état (mémorisation) et de les conserver dans le "stockage traditionnel". Chaque instantané est étiqueté avec le numéro de séquence du dernier événement utilisé pour créer l'instantané; lors du rechargement, le référentiel récupère d'abord cet instantané, puis lui applique les événements les plus récents. (Cela implique un moyen raisonnable de récupérer les instantanés les plus récents - soit les événements sont également marqués avec le numéro de séquence, soit vous avez un moyen efficace de lire le flux d'événements en arrière jusqu'à ce que vous arriviez à votre point de départ.)

Il y a toujours un avantage sur l'approche habituelle ici, étant que vos instantanés peuvent être construits en parallèle de vos écritures, plutôt que d'être fusionnés avec eux: vous mettez simplement un écouteur d'événements dans un autre thread / processus, et le laissez gaiement en écrivant au magasin d'instantanés sur n'importe quel calendrier semble raisonnable. Après tout, l'instantané n'a pas besoin d'être particulièrement opportun - juste assez souvent pour que le travail de réapplication des événements les plus récents ne fasse pas exploser votre SLA.

(La capture instantanée complique la migration; toute modification de la sérialisation du modèle invalidera le cache de capture instantanée. Bien sûr, vous pouvez reconstruire des captures instantanées en utilisant la nouvelle sérialisation dans le cadre de la migration, puis "rattraper" lorsque les modifications seront mises en ligne.)

La restauration de l'état à partir du flux d'événements est-elle même couramment effectuée?

Oui, ça l'est. Ce qui est normalement montré dans les exemples CQRS, c'est que la couche Application, après avoir vérifié que la commande soumise est bien formée, la couche Application chargera l'objet de domaine à partir d'un référentiel, où la charge est un constructeur par défaut suivi d'une relecture du flux d'événements. (ou de manière équivalente, un appel à une usine avec une liste d'événements).

Deux autres pensées contradictoires.

  1. Il pourrait y avoir un cache derrière l'interface du référentiel
  2. L'invalidation du cache est l'un des deux problèmes difficiles.
VoiceOfUnreason
la source