J'ai lu récemment sur la recherche d' événements et j'aime vraiment les idées qui se cachent derrière, mais je suis coincé avec le problème suivant.
Supposons que vous ayez N processus simultanés qui reçoivent des commandes (par exemple des serveurs Web), génèrent des événements en conséquence et les stockent dans un magasin centralisé. Supposons également que tous les états d'application transitoires soient conservés dans la mémoire des processus individuels en appliquant séquentiellement les événements du magasin.
Supposons maintenant que nous avons la règle commerciale suivante: chaque utilisateur distinct doit avoir un nom d'utilisateur unique.
Si deux processus reçoivent une commande d'enregistrement d'utilisateur pour le même nom d'utilisateur X, ils vérifient tous les deux que X ne figure pas dans leur liste de noms d'utilisateurs, la règle valide pour les deux processus et ils stockent tous les deux un événement «nouvel utilisateur avec le nom d'utilisateur X» dans le magasin .
Nous sommes maintenant entrés dans un état global incohérent car la règle métier est violée (il y a deux utilisateurs distincts avec le même nom d'utilisateur).
Dans un système de style RDBMS traditionnel à serveur N <-> 1, la base de données est utilisée comme point central de synchronisation, ce qui permet d'éviter de telles incohérences.
Ma question est la suivante: comment les systèmes basés sur des événements abordent-ils généralement ce problème? Traitent-ils simplement toutes les commandes de manière séquentielle (par exemple, limitent-elles à 1 la quantité de processus pouvant écrire dans le magasin)?
la source
Réponses:
Dans les systèmes provenant d'événements, le "magasin d'événements" joue le même rôle. Pour un objet provenant d'un événement, votre écriture est une annexe de vos nouveaux événements à une version particulière du flux d'événements. Ainsi, tout comme avec la programmation simultanée, vous pouvez acquérir un verrou sur cet historique lors du traitement de la commande. Il est plus courant que les systèmes basés sur des événements adoptent une approche plus optimiste: chargez l'historique précédent, calculez le nouvel historique, puis comparez et échangez. Si une autre commande a également écrit dans ce flux, la comparaison et l'échange échouent. À partir de là, vous réexécutez votre commande, ou abandonnez votre commande, ou peut-être même fusionnez vos résultats dans l'historique.
La contention devient un problème majeur si tous les N serveurs avec leurs commandes M tentent d'écrire dans un seul flux. La réponse habituelle ici consiste à allouer un historique à chaque entité d'origine d'événement de votre modèle. Ainsi, l'utilisateur (Bob) aurait un historique distinct de l'utilisateur (Alice), et les écritures sur l'un ne bloqueront pas les écritures sur l'autre.
Greg Young sur la validation du plateau
Existe-t-il un moyen élégant de vérifier les contraintes uniques sur les attributs d'objet de domaine sans déplacer la logique métier dans la couche de service?
Une réponse courte, dans de nombreux cas, une enquête plus approfondie sur cette exigence révèle que soit (a) il s'agit d'un mandataire mal compris pour une autre exigence, ou (b) que les violations de la "règle" sont acceptables si elles peuvent être détectées (rapport d'exception) , atténué dans une certaine fenêtre de temps, ou sont de faible fréquence (par exemple: les clients peuvent vérifier si un nom est disponible avant d'envoyer une commande pour l'utiliser).
Dans certains cas, lorsque votre magasin d'événements est bon pour la validation des ensembles (c'est-à-dire: une base de données relationnelle), vous implémentez l'exigence en écrivant dans une table "noms uniques" dans la même transaction qui persiste les événements.
Dans certains cas, vous ne pouvez appliquer l'exigence qu'en publiant tous les noms d'utilisateur dans le même flux (ce qui vous permet d'évaluer l'ensemble de noms en mémoire, dans le cadre de votre modèle de domaine). - Dans ce cas, deux processus mettront à jour la tentative de mise à jour de "l'historique" du flux, mais l'une des opérations de comparaison et d'échange échouera et la nouvelle tentative de cette commande pourra détecter le conflit.
la source
On dirait que vous pourriez implémenter un processus métier (
saga
dans le contexte deDomain Driven Design
) pour l'enregistrement de l'utilisateur où l'utilisateur est traité comme unCRDT
.Ressources
https://doc.akka.io/docs/akka/current/distributed-data.html http://archive.is/t0QIx
"CRDT avec Akka Distributed Data" https://www.slideshare.net/markusjura/crdts-with-akka-distributed-data pour en savoir plus sur
CmRDT
s - CRDT basés sur les opérationsCvRDT
s - CRTD basés sur l'étatExemples de code dans Scala https://github.com/akka/akka-samples/tree/master/akka-sample-distributed-data-scala . Peut-être que "panier" est le plus approprié.
la source