Juillet 2016

Volume 31, numéro 7

Cet article a fait l'objet d'une traduction automatique.

CQRS - Exploiter les fonctionnalités de CQRS pour créer des systèmes extrêmement réactifs

Par Peter Vogel | Juillet 2016

Le modèle de commande requêtes séparation (CQRS) a augmenté en popularité ces trois ou quatre dernières années. Certes, il est un outil essentiel dans les scénarios de collaboration, où il existe un ensemble de données mises à jour par plusieurs processus (Dino Esposito rend un cas d’utilisation CQRS encore plus largement dans son juin 2015 Dino Esposito, « CQRS pour l’Application courante, » à bit.ly/1OtQba3). Serait d’aller plus loin et de revendication, CQRS est en fait, le modèle de conception par défaut pour les développeurs ASP.NET MVC qui interrogent les données à afficher dans les vues et alors émettre des commandes de mise à jour des tables lors de la validation de ces données à leurs contrôleurs MVC.

Toutefois, la CQRS est une tactique qui doit être appliquée dans le cadre d’une stratégie de plus grande. La première étape de stratégie est la conception (DDD), qui est décrite dans la colonne de juin 2013 de Julie, « Réduire EF modèles avec des contextes associés DDD, » à bit.ly/1TfF7dk. DDD conduit à diviser votre application en exploitation domaines, chacun d'entre eux faudra peut-être sa propre base de données de plus, bien sûr, son propre modèle d’entreprise dédié. DDD fournit des stratégies et des tactiques permettant de domaines être développées indépendamment les uns des autres alors que continuant à travailler ensemble.

Définition des domaines de l’inventaire

Mais DDD uniquement potentiellement inutile la collaboration. Considérons, par exemple, une application de vente en ligne. Ici, il existe un élément essentiel partagé des données : les niveaux de stock. Pour garantir que l’entreprise n’essaie pas de vendre quelque chose que n’est pas, l’entreprise peut soit conserver inventaire précis du nombre de quantité disponible (QoH) pour chaque Stock (référence SKU Keeping Unit)... ou toujours disposer d’inventaire supplémentaire, « juste-cas ». Lean aujourd'hui cette deuxième option n’est pas pris en compte : Les entreprises ne souhaitent conserver inventaire plus qu’il ne doit.

Mise à jour QoH basée sur des transactions commerciales est plus complexe que vous pourriez penser comme un système réel inventaire gère un grand nombre de transactions. Les transactions évidentes sont, bien sûr, décrémentation QoH lors de la vente une référence (SKU) et en incrémentant QoH lors de la réception de nouvelles références SKU. En outre, une entreprise effectue régulièrement un « inventaire » afin de déterminer la QoH réelle pour chaque référence (SKU). Étant donné que même dans un système bien géré précision du stock n’est pas 100 pour cent, ce nombre nécessitera une modification aux niveaux de stock. En outre, parfois SKU est découverts défectueux d’une certaine façon et supprimé de l’inventaire. Parfois, une fois une référence SKU est vendue et supprimée de l’inventaire, le client annule la commande et la référence (SKU) est renvoyé à l’emploi.

Les entreprises veulent effectuer le suivi de toutes ces différentes opérations, en conservant les informations spécifiques à chaque transaction. Lors de la réception de nouvelles références SKU, par exemple, les entreprises veulent savoir quelles facture a été utilisé pour acheter les SKU : Lorsque des références sont détectés défectueux, les entreprises veulent savoir pourquoi ; et, au cours de l’inventaire, les entreprises veulent savoir comment cette incohérence était. Comptabilité nécessite ces informations au rapport précisément le « état de la société » ; le département des opérations a besoin de ces informations pour planifier avec précision pour l’avenir. Parce que des informations supplémentaires, ces transactions ne peut pas être traitées comme simplement les ajouts et suppressions de l’inventaire.

Toutefois, toutes ces opérations appartiennent dans le même domaine. Ces transactions sont réparties entre les domaines appelés « ventes », « comptabilité », « opérations », « réception » et ainsi de suite. Division des transactions entre domaines reflète la réalité que des domaines différents ont des exigences différentes.

La plupart des domaines, par exemple, n’avez pas besoin des données plus récentes, si elles étaient exécutées même une journée de travail derrière les transactions réelles, il n’est pas un problème. Le service comptabilité, par exemple, ne doit connaître la situation financière de l’inventaire en fin de mois et, même dans ce cas, ne soient pas accessibles pour que ces informations jusqu'à ce que les premiers jours du mois suivant. Bien qu’il soit possible de conserver les données d’inventaire plus récentes, il serait difficile de trouver une justification pour cette méthode. Informations d’inventaire de ces services peuvent être « cohérentes ».

Le système client ne peut pas avoir les informations d’inventaire « cohérentes », cependant. Le département des ventes a besoin de connaître le QoH dès maintenant afin qu’il peut décider si une référence (SKU) peut être affiché dans le client (« gauche uniquement deux ! Commandez dès maintenant ! »). En fait, tandis que la plupart des domaines aurait un nombre unique pour le QoH pour une référence (SKU), le système client peut conserver la QoH sous forme de deux nombres. Un nombre est la quantité de « réservée » (références SKU demandé par un utilisateur qui est en cours de création d’une commande) et le deuxième nombre est le « toujours disponible à la vente ». Si un client achète deux éléments, le nombre réservé est augmenté par deux et le nombre de disponible à la vente réduit. à la fin de la vente, la quantité réservée est réduite par deux ou, si l’utilisateur annule la commande, ajoutée au nombre disponible à la vente.

Gestion et opérations devez la flexibilité de la base de données relationnelle pour joindre les tables de plusieurs façons. Ils seront également besoin permet de rechercher des données, parfois de manière à n’avait pas été pris en compte avant la détection d’un problème particulier. Étant donné la quantité de données impliquées et la nécessité d’effectuer des recherches sur l’historique des transactions, la pagination sera également requise.

Le système client ne nécessite pas autant de flexibilité. Les relations entre les entités sont résolues avec la conception de l’interface utilisateur, tel que sont les critères de recherche (bien que la prise en charge de la pagination est toujours requis).

Exigences de temps de réponse varient également entre les domaines. Pour la plupart des services, un temps de réponse en quelques secondes n’aurait pas nuire à l’entreprise ; pour le système client, le temps de réponse doit être mesuré en fractions de seconde.

Création d’un système unique pour répondre à tous ces besoins serait difficile (je dirais impossible). Création d’une application pour chaque domaine peut, au moins. Par exemple, le service de gestion de produits aurait une liste de produits qui est constamment mis à jour avec les nouveaux produits et des informations sur les produits existants ; le domaine vente maintiennent en revanche, une liste de produits en lecture seule/requête uniquement régulièrement synchronisé avec les données dans le domaine de gestion de produit.

Considérez les domaines comme le principe de responsabilité unique appliqué au niveau de l’entreprise. Chaque domaine gère également une partie de l’entreprise. Bien que l’entreprise est compliquée, chaque domaine peut être : relativement parlant, simple.

La Solution CQRS

Tous ces domaines sont en partageant les niveaux de stock, toutefois. Comme les transactions traverser des domaines tels que la comptabilité et la réception, ils doivent notifier le système de vente des modifications aux niveaux de stock. Même dans le système client, plusieurs clients peuvent essayer d’acheter les mêmes références, individuellement conduite haut et bas, des niveaux de stock et nécessitant un niveau de verrouillage en tant que ces numéros sont ajustées.

Le modèle CQRS devient utile ici en allant au-delà de ce qui envisagent le développeur ASP.NET MVC par défaut. Dans la plupart des domaines, par exemple, les applications peuvent interroger leurs propres bases de données qui contiennent les informations nécessaires dans le domaine. Une fois qu’il s’agit d’émettre une commande pour régler les niveaux de stock, tous les domaines doivent mettre à jour les données du domaine de vente en ligne. Et l’obligation de deux façons : Comme les articles sont vendus, le système de vente doit notifier comptabilité, les opérations et les autres domaines sur les modifications apportées dans QoH en raison des ventes pour chaque référence SKU.

Plutôt que de mettre à jour les données d’un autre domaine, cependant, chaque domaine est uniquement obligé de notifier d’autres domaines sur un aspect de ces autres domaines intéressent (dans ce cas, QoH). Chaque domaine doit être responsable de la mise à jour ses propres données, car chaque domaine sait comment gérer ses données et aucune autre domaine ne.

Le domaine des opérations, par exemple, constamment explore les relations entre ses données pour prévoir les demandes de stock et pour déterminer les causes de fluctuations de niveau de stock. Ce domaine doit prendre en charge la flexibilité dans les requêtes de données qui fournit une base de données relationnel traditionnel. La complexité dans le domaine des opérations est déterminée par le type d’analyse requis dans ce domaine.

Le domaine du client, doit quant à lui, quelque chose de plus simple. Il doit connaître le QoH (réservée et disponible à la vente) pour n’importe quel SKU. Il peut même être utile pour le système de vente simplement conserver l’ID pour chaque référence (SKU) et ses deux nombres QoH en permanence dans la mémoire. Si ce n’est pas possible en raison du nombre d’articles en stock, il peut être toujours judicieux de conserver en mémoire les 20 pour cent de l’inventaire des lecteurs de 80 % des ventes de l’entreprise. Les autres articles en stock peut être conservés dans une base de données NoSQL conçu pour prendre en charge des transactions de vente sans avoir à fournir la flexibilité qui, par exemple, le domaine d’opérations nécessite. La complexité du domaine sales est dictée par la nécessité pour les temps de réponse faible.

Ces différences font que le domaine des opérations ne sont pas censé savoir comment mettre à jour les numéros de QoH dans le domaine du client (et vice versa, bien sûr).

Domaines, par conséquent, peuvent également interroger une base de données (leur) tant qu’envoyer des commandes à une autre base de données (tout le monde envoie QoH met à jour le domaine client, par exemple). Alors que DDD fournit une stratégie pour la segmentation des domaines avec des besoins différents, CQRS fournissent l’une des tactiques de gestion des mises à jour entre les domaines (pour une discussion plus approfondie de la partie de la requête de la CQRS, consultez de Esposito mars 2016, la requête pile d’un CQRS Architecture », » à bit.ly/1WzjvPi).

Gestion des commandes et des événements

Bien sûr, vous ne souhaitez pas compliquer les applications dans ces domaines d’avoir à gérer la diversité des domaines qui doivent être notifiés pour chaque transaction. Au lieu d’effectuer le suivi de tous les domaines qui doivent être mis à jour, chaque application envoie des transactions à un utilitaire qui est chargé de notifier les différents domaines (généralement appelés un « bus de commande »). Comme nouveaux domaines sont définies (ou des domaines existants modifier leurs demandes), le bus de commande au sein du domaine qui est issue de la transaction doit être mis à jour pour refléter les nouvelles notifications sont requises.

Ces opérations peuvent être divisées en catégories : les événements et les commandes. La distinction entre les deux est plus conceptuelle que techniques. En effet, les commandes et les événements sont des messages qui encapsulent les informations de clé d’une transaction. Notre mouvements de stock qui seraient l’Id de la référence (SKU), l’écart pour le niveau de stock et les données supplémentaires requises par la transaction (lors de la réception des données peuvent être le numéro du fournisseur et le numéro de facture ; pendant la prise de stock les données supplémentaires peuvent être l’Id de l’employé qui a compté les références SKU des marchandises). Ces messages peuvent être codés en tant qu’objets POCO ou XML/JSON documents (ou les deux, selon la façon dont les données sont envoyées entre les domaines).

Pour moi, la définition d’une commande est qu’elle de quelque chose dirigée vers un seul destinataire afin de réaliser une tâche. Une commande est généralement une tâche qui doit être exécutée immédiatement et, bien évidemment, est envoyée avant l’exécution de la tâche. Une commande peut également être attendue pour renvoyer une réponse de réussite/échec que l’application peut utiliser pour informer l’utilisateur si tout a travaillé (et entraîner l’application d’effectuer une requête pour récupérer les données qui affiche les résultats ont été atteints). La plupart des mises à jour au sein du domaine à l’origine de la transaction sont probablement gérées avec les commandes.

Quant à lui, se produisent après que la tâche est exécutée, peut être traitée par plusieurs destinataires et, en règle générale, ne sont pas nécessairement être traité immédiatement. Les événements ne sont pas censés pour retourner un résultat, au moins pas immédiatement. Si une erreur survient avec un événement, l’application sera généralement rendrai pas compte via un message de retour différé (« nous sommes désolés, mais qu'il s’avère, nous ne pouvons pas traiter votre commande, car votre carte de crédit a été refusée »). La plupart, mais pas toutes les mises à jour en dehors du domaine d’origine de la transaction sont probablement gérées avec des événements.

Et, comme la plupart des différences conceptuelles, il s’agit probablement d’un continuum ; certains messages sont des commandes « évidemment », certains messages sont des événements « évidemment » et il existe certaines sur les personnes qui raisonnables peut en désaccord.

Une transaction unique dans un domaine peut générer une combinaison de commandes et les événements. Prendre en compte les nouvelles références SKU apparaît-il sur la station de réception. Une fois les références sont correctement reçus, le bus de ce domaine envoie une commande dans le système de vente pour que le QoH pour ce SKU augmenté immédiatement ; le bus serait également publier un événement afin que les systèmes de gestion et les opérations peuvent être avertis que « quelque chose est arrivé » et doivent être pris en compte à la fin du mois. En examinant les messages impliqués, il peut être difficile de déterminer lequel est l’événement et lequel est la commande, sauf si, par exemple, en examinant le nom du message ; les événements ont tendance à avoir des noms dans le passé (GoodsReceived), tandis que les commandes ont tendance à avoir des noms impératifs (IncreaseInventory).

Le bus peut envoyer la commande dans le système de vente en appelant un service RESTful dans ce domaine pour une exécution immédiate ; l’événement peut être écrit sur une file d’attente de messages à traiter par d’autres domaines à leur convenance (j’ai abordé certaines des options dans un article, j’ai écrit pour VisualStudioMagazine.com, « Simplification Applications par l’implémentation finale cohérence avec domaine événements, » à bit.ly/1qn1wwV).

Qui sait, bien sûr, même avec la commande envoyée au service Web, ce qui se passe derrière ce service Web ? Pour gérer un grand nombre de demandes simultanées, le service Web pour le domaine peut simplement écrire le message de commande dans une file d’attente et retourner une réponse « Merci d’avoir, c’est ça », en conservant le temps de réponse court et améliorer l’évolutivité. En plus d’améliorer l’évolutivité, écrire des commandes dans une file d’attente permet au domaine récupérer à partir de ce qui auraient pu être catastrophes. Si la base de données ou du réseau est arrêté, par exemple, le système client peut attendre patiemment être restaurés, puis traiter toutes les commandes dans sa file d’attente du service. Par conséquent, même les commandes peuvent se retrouver sur les files d’attente.

Comme je l’ai dit, la distinction entre les commandes et les événements est conceptuel, pas de connaissances techniques.

Traitement des commandes et les événements

Grâce à CQRS, les applications peuvent désormais travailler avec une combinaison des deux bases de données : une pour les requêtes (probablement locales dans le domaine) et d’autres bases de données qui sont des cibles pour les commandes et les événements. Par exemple, le système de vente allez travailler avec un magasin de données qui inclut la base de données NoSQL qui conserve les données QoH ; les opérations et les applications de comptabilité peuvent travailler avec un magasin de données organisé autour de l’historique des événements/commandes.

La différence entre les deux systèmes est que le système client a besoin d’un instantané de l’état actuel des niveaux de stock pour répondre aux exigences de temps de réponse ; les opérations et les domaines de comptabilité besoin un historique des événements survenus à chaque référence (SKU) pour prendre en charge d’analyse. Les opérations et les domaines de comptabilité peuvent recourir à une autre solution : événement d’approvisionnement. Avec l’approvisionnement de l’événement, effectue une logique de domaine via le journal d’audit des événements qu’ils notification sur le point de fournir une réponse finale (pour le système de gestion qui peut-être être, « en fonction de l’historique des transactions validées, la valeur actuelle de votre inventaire est X dollars »).

Présente des avantages et inconvénients liés à la source d’événement. Événement approvisionnement il est toujours possible de recréer un instantané de l’état actuel des données en réexécutant la liste des transactions ; comptabilité apprécie cette fonctionnalité car elle ajoute des ajustements à la liste des événements. Avec la source d’événement, il est également possible de décrire l’avenir lors du traitement des événements potentiels (livraisons attendus et les ventes) ; opérations apprécient cette fonctionnalité lors de la planification.

En cas d’augmentation de la liste des événements, ne les temps de réponse, toutefois. Comptabilité peut restaurer par progression à partir de son « dernier état correct connu » (probablement les nombres à partir de la dernière fermeture de la fin du mois-) et générer un instantané qui représente les numéros de fin de mois. Cet instantané est enregistré en tant que le cours « dernier état correct connu » et publié en tant que rapports de fin de mois. Opérations peuvent restaurer par progression à partir d’aujourd'hui à un point indéterminé dans le futur et, probablement, ne génèrent jamais d’instantané ; ils seraient recréer l’avenir chaque fois qu’elle a été demandée. Étant donné les attentes de temps de réponse pour ces domaines, ce sont les scénarios probablement raisonnables.

Pour déterminer le QoH actuelle pour le système de vente à l’aide de la source d’événements, en revanche, le système client aura restaurer par progression via toutes les transactions depuis le dernier inventaire. Étant donné que les comptes d’inventaire sont laborieux, ces nombres ne se produisent pas très souvent. Par conséquent, tous les événements de traitement depuis le dernier nombre créerait des temps de réponse inacceptable pour le système client. Au lieu de cela, le système client conserve ses numéros QoH constamment mis à jour dans la mémoire.

Synthèse

Tandis que l’interrogation requiert que différents niveaux des mises à jour de la prise en charge dans la base de données (et, en conséquence, des index et des clés étrangères/primaires), ne le faites pas. Pratiquement toutes les mises à jour sont pilotées par les ID des entités impliquées. La liste du stock SKU avec les numéros de QoH, par exemple, repose entièrement par l’ID de référence (SKU). Ceci peut simplifier considérablement le modèle de données pour le côté de la commande d’un système CQRS. La possibilité d’Entity Framework générer une collection de SalesOrderItems pour SalesOrder est sans effet si le message d’événement de commande/inclut simplement les ID de tous les SalesOrderItems qui ont été modifiés dans une transaction.

L’impact sur le verrouillage dans la base de données grâce à cette conception est intéressante. Mises à jour les quantités réservées dans le système de vente QoH se composent de modification d’une ou deux des valeurs entières ; le verrouillage doit être minime. Verrouillage des autres systèmes peut disparaître si ces systèmes sont des événements provenant ; toujours la transaction insère une transaction dans une table d’événements il y a aucune mise à jour.

En effet, puis, l’entreprise possède plusieurs, processeurs indépendants, mise à jour des données au sein de leurs domaines, traitement des commandes et les événements. Sans verrouillage, il est possible que cela peut créer des conflits. Par exemple, une commande pour acheter deux articles peut-être apparaître en même temps comme un événement qui réduit le QoH à zéro (une personne a un inventaire et remarqué qu’il a été rien en rayon). Curieusement, une approche basée sur la file d’attente, event sourcing peut résoudre le problème ; le processeur de la mise à jour QoH dans le système de vente fonctionnait sur une base event sourcing, propagée à toutes les commandes récemment reçus dans une file d’attente (dans une limite) et la mise à jour de QoH avec le total de leurs résultats. Les commandes qui s’affichent simultanément seraient résumées dans une seule mise à jour. Sinon, il peut être simplement nécessaire de reconnaître que, parfois, l’entreprise peut annuler une commande comme un utilisateur peut.

CQRS est un outil puissant. Il a le plus gros avantage, toutefois, lorsqu’il est appliqué aux magasins de données partagées, processus de collaboration et dans la stratégie fournie par la conception pilotée par domaine.


Peter Vogel est un architecte système et PH & V Information Services.  PH & V fournit à pile complète consulting de concevoir l’expérience utilisateur par le biais de modélisation à la conception de base de données d’objets. Vous pouvez le contacter à l’adresse peter.vogel@phvis.com.

Remercie les experts techniques Microsoft suivants pour avoir relu cet article : Dino Esposito et Julie Lerman
Dino Esposito est l’auteur de « Microsoft .NET : Conception d’Applications pour l’entreprise » (Microsoft Press, 2014) et « Applications Web modernes avec ASP.NET » (Microsoft Press, 2016). Un développeur technique pour les plateformes .NET et Android chez JetBrains, dans le monde entier manifestations du secteur, Esposito partage sa vision du logiciel à software2cents@wordpress.com et sur Twitter : @despos.

Julie Lerman est Microsoft MVP, mentor et conseillère qui habite dans les collines du Vermont .NET. Vous pouvez trouver sa présentation sur l'accès aux données et d'autres rubriques .NET à des groupes d'utilisateurs et à des conférences dans le monde entier. À l’adresse thedatafarm.com et est l’auteur de « Programming Entity Framework », ainsi qu’un Code First et une édition DbContext, à partir d’o ' Reilly Media. Vous pouvez la suivre sur Twitter : @julielerman et consulter ses cours sur Pluralsight sur juliel.me/PS-Videos.