J'ai actuellement deux microservices. Nous les appellerons A
et B
.
La base de données sous microservice A
a le tableau suivant:
A
|-- users
La base de données sous microservice B
a le tableau suivant:
B
|-- trackers
Les exigences indiquent que users
et trackers
ont une relation plusieurs-à-plusieurs.
Je ne sais pas comment gérer correctement cela dans une architecture de microservices.
Je pouvais voir cela fonctionner de trois manières:
user_trackers
la table est ajoutée au microservice A
. Cela agit comme une table de jointure contenant des "clés étrangères" pour users
et trackers
.owners
est ajoutée au microservice B
. Cette table agit de manière similaire à une table de jointure polymorphe. Cela permettrait à n'importe quel service de créer une association avec un tracker. Cela peut ressembler à ceci: B |-- trackers |-- owners |-- owner_id |-- owner_type |-- tracker_id
users
et trackers
dans chaque microservice. Gardez-les synchronisés avec une sorte de système de pubsub.J'allais à l'origine choisir l'option 2 parce que j'aimais le fait qu'elle préservait les limites des transactions. Je peux créer un tracker et l'associer à quelque chose atomiquement. Cependant, il semble hors de portée du microservice B
. Pourquoi microservice B
devrait-il veiller à ce que microservice A
veuille créer une association?
J'ai l'impression qu'il y a probablement un bon schéma ici que je ne connais pas. Est-ce que l'une des options que j'ai présentées est logique? Y a-t-il une autre option qui pourrait avoir plus de sens?
Tout d'abord, je commencerais par la description du domaine. Vous n'avez pas mentionné de quoi il s'agit (je suppose, mais ce ne serait qu'une supposition). Après cela, j'essayerais de le décomposer en utilisant analyse de la chaîne de valeur ou cartographie des capacités commerciales . Et seulement après cela, je penserais à la mise en œuvre.
Compte tenu de votre problème, la première chose qui me vient à l'esprit est que vous avez mal identifié les limites de vos services, simplement parce qu'ils ont besoin les uns des autres. Vous ne voulez pas vous retrouver avec monolithe distribué , n'est-ce pas?
La deuxième chose est que vous n'avez probablement pas assez bien travaillé sur votre domaine. Quel concept est représenté avec la table users
? Est-ce un registered user
, avec toutes les informations et le comportement requis pour l'inscription? Êtes-vous sûr que c'est le bon concept pour communiquer avec trackers
(quel qu'il soit)? Donc, si je comprends bien, votre option 2 est exactement à ce sujet: introduire le concept owner
qui est beaucoup plus proche de votre domaine. Si c'est vraiment le cas, je suis également pour l'option 2.
Cependant, cela semble hors de portée pour le microservice B. Pourquoi le microservice B devrait-il veiller à ce que le microservice A veuille créer une association?
C'est une question de frontières. Je suppose que vous voulez former des microservices autour d'entités. C'est là que SOA a échoué avec son architecture de service en couches . La meilleure approche consiste à créer des services qui représentent une fonction métier, afin qu'ils encapsulent à la fois les données et le comportement. D'un point de vue plus pratique, il s'agit de créer des services autour de processus métier ou de cas d'utilisation. Par exemple, vous pourriez avoir un service pour l'enregistrement des utilisateurs. Il contient les données de l'utilisateur et le comportement requis pour enregistrer un utilisateur. Ainsi, le concept de user
se forme naturellement et n'appartient qu'au service A. Et cela m'amène au point suivant: l'autre façon de penser aux services est contexte borné . C'est une bonne pratique pour aligner les services et les contextes délimités.
Lorsque l'utilisateur est enregistré, l'événement UserCreated
peut être émis. Je suppose que votre deuxième service l'intéresse. Ainsi, lors de sa réception, une entité complètement différente pourrait être créée, disons, Owner
entité (quelle qu'elle soit, soit). Je suis presque sûr qu'il y a beaucoup de collaborations intéressantes entre elle et l'entité tracker
- gardez-les dans un seul service.
Soyez extrêmement prudent avec l'option 3. Si vous copiez des données, la fonctionnalité suit. Il en résulte un couplage serré. Et ne couvrez pas avec CQRS terme, il ne s'agit pas de synchronisation de données entre services via des événements.
La réponse de Zapadlo contient beaucoup de bonnes informations et un bon raisonnement. Je vais ajouter ici un petit conseil pratique qui peut faciliter le traitement de vos problèmes et les conseils dans cette réponse.
La façon dont vous avez formulé votre question de conception concerne les structures de base de données et la manière de répondre à une nouvelle exigence pour vos structures. Cela implique que vous construisez la conception du service à partir de votre modèle de données. Par exemple, ce que je ne vois pas, c'est comment la relation entre les utilisateurs et les trackers doit être accessible ou utilisée.
Dans la conception de services, la structure de l'interface est l'élément le plus important de la conception. En fait, la mise en œuvre est presque hors de propos en comparaison notamment dans le cas des microservices. La raison en est qu'une fois que vous avez mis votre service en place, toutes les dépendances de votre service devraient exister uniquement sur l'interface. Si vous réussissez, vous devriez être en mesure de réécrire complètement l'implémentation sans aucun consommateur. Et c'est le principal avantage de l'autonomie. Personne ne se soucie de la façon dont vous l'avez construit. Ils en ont juste besoin pour fonctionner comme vous l'avez annoncé.
Avant que quiconque puisse déterminer à quoi cela ressemble dans la base de données ou où vous le souhaitez, vous devez vraiment expliquer comment ces informations vont être utilisées. Est-ce quelque chose qui sera exposé via un service ou s'agit-il d'une sorte de données que vous souhaitez mélanger pour l'analyse?
D'un autre côté, j'éviterais les dépendances bidirectionnelles à presque tous les prix. Si vous avez des dépendances, vous voulez vraiment qu'un seul côté connaisse l'autre. Une fois les dépendances dans les deux sens, leurs services deviennent essentiellement une unité atomique.
Cela se résume en grande partie au domaine lui-même. Si un utilisateur avec zéro trackers n'a pas de sens, le service utilisateur doit connaître les trackers. Si un tracker doit avoir un utilisateur, les trackers doivent connaître les utilisateurs. Si quelque chose comme avoir un tracker avec plusieurs propriétaires ou être capable de transférer un tracker d'un utilisateur à un autre est logique, alors peut-être que ces informations appartiennent à un autre service.
Question: Pourquoi vos données sont-elles séparées le long des tables de données?
J'aurais tendance à choisir l'option 3: les services sont totalement séparés et peuvent répondre aux questions respectives auxquelles ils pourraient avoir besoin de répondre. De plus, ils sont beaucoup plus résistants. Mais attention, vos services pourraient se désynchroniser s'ils manquent des événements, mais cela peut être résolu grâce à une cohérence éventuelle.
En outre, vous pourriez envisager de fusionner les deux services - si les deux ne sont pas en mesure de répondre sans se connaître, je les fusionnerais simplement car ils font probablement partie d'un seul domaine.