Microservices sans duplication de données

19

J'ai du mal à éviter la duplication des données ou une base de données partagée, même pour la conception de microservices la plus simple, ce qui me fait penser que je manque quelque chose. Voici un exemple de base du problème auquel je suis confronté. En supposant que quelqu'un utilise une application Web pour gérer un inventaire, il aurait besoin de deux services; un pour l'inventaire gérant les articles et la quantité en stock et un service utilisateurs qui gérerait les données utilisateurs. Si nous voulons un audit de qui a stocké la base de données, nous pouvons ajouter l'ID utilisateur à la base de données pour le service d'inventaire en tant que dernier stocké par valeur.

En utilisant l'application, nous pouvons vouloir voir tous les articles qui manquent et une liste de ceux qui les ont stockés la dernière fois afin que nous puissions leur demander de le réapprovisionner. En utilisant l'architecture décrite ci-dessus, une demande serait effectuée auprès du service d'inventaire pour récupérer les détails de tous les articles dont la quantité est inférieure à 5. Cela retournerait une liste comprenant les ID utilisateur. Ensuite, une demande distincte serait faite au service des utilisateurs pour obtenir le nom d'utilisateur et les coordonnées de la liste des ID utilisateur obtenus auprès du service d'inventaire.

Cela semble terriblement inefficace et il ne faut pas beaucoup plus de services avant de faire plusieurs demandes à différentes API de services qui à leur tour effectuent plusieurs requêtes de base de données. Une alternative consiste à répliquer les détails des utilisateurs dans les données d'inventaire. Lorsqu'un utilisateur modifie ses coordonnées, nous devons alors reproduire la modification via tous les autres services. Mais cela ne semble pas correspondre à l'idée de contexte borné des microservices. Nous pourrions également utiliser une seule base de données et la partager entre différents services, et avoir tous les problèmes d'une base de données d'intégration .

Quelle est la bonne / meilleure façon de mettre cela en œuvre?

Geraint Anderson
la source
5
Bienvenue dans le paradoxe des micro-services. Ce qui semble simplifier les choses peut en fait rendre les choses plus complexes.
Robert Harvey
La manière "correcte" est la même que celle qui a toujours été: trouver une façon de faire les choses qui convient le mieux à vos objectifs spécifiques.
Robert Harvey
1
@RobertHarvey C'est toujours le cas, mais j'essaie de comprendre la méthode des microservices des manuels. Une fois que je comprends comment cela devrait fonctionner dans un monde idéal, je le changerai avec plaisir pour l'adapter à mon cas d'utilisation.
Geraint Anderson
1
Mais vous cadrez votre question en termes d'efficacité, qui est une exigence logicielle non fonctionnelle. La façon dont vous résolvez le problème d'efficacité consiste à demander directement à la base de données.
Robert Harvey
1
J'étais sur le point d'écrire une question exactement comme la vôtre. Je ne vois toujours pas d'avantages dans MSA pour des applications Web raisonnablement simples. Je pense que dans de nombreux cas, la modularité pourrait être obtenue sans rendre les choses si complexes.
Glasnhost

Réponses:

10

J'ai complètement raté l'endroit où vous devez dupliquer.

Un principe central des microservices est que le service soit la seule autorité. Cela signifie que la gestion des stocks et des utilisateurs peut être complètement séparée. Je concevrais la gestion des utilisateurs de manière à ce qu'il ne sache même pas que le système d'inventaire existe.

Mais je conçois le système d'inventaire de sorte qu'il ne stocke jamais rien sur les utilisateurs autre qu'un ID utilisateur. Cela résout votre problème de propagation des modifications des informations utilisateur.

Quant aux choses qui nécessitent à la fois des informations d'inventaire et des informations utilisateur telles que les journaux, les audits et les impressions, elles ne sont pas mises à jour lorsque les informations changent. Ils sont un enregistrement de ce qui était. Encore une fois, vous ne propagez pas le changement.

Donc, dans tous les cas, lorsque vous voulez les dernières informations utilisateur, vous demandez au service d'informations utilisateur.

candied_orange
la source
@Geraint: Pouvez-vous être plus précis sur le type de duplication qui se produit dans votre système?
Robert Harvey
1
Merci. La duplication faisait référence à la copie des coordonnées des utilisateurs vers le service d'inventaire, mais vous y avez répondu (c'est-à-dire que ce n'est pas obligatoire). Il semble contre-intuitif de passer d'une seule base de données relationnelle où je pourrais obtenir les données d'inventaire et les données utilisateur avec une jointure à deux appels API distincts où le second ne peut pas commencer tant que le premier n'a pas renvoyé les résultats. Mais je suppose que cela fait partie de l'évaluation pour savoir si j'utilise des microservices ou autre chose.
Geraint Anderson
C'est la même astuce que la DB utiliserait si elle gérait les deux. Vous ne copiez pas les informations utilisateur dans la table d'inventaire. Vous lui donnez une clé étrangère. L'ID utilisateur effectue le même travail sur tous les services. Rendez-le unique.
candied_orange
It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinGardez à l'esprit que «idéalement», il y a un magasin par service (ou plus!). Il n'y a donc rien de tel que la «jonction» entre les «frontières». La raison est simple, DB génère un couplage entre services. Contrairement à @CandiedOrange, je pense que nous pouvons dupliquer un minimum de données d'un service à un autre. Je fais référence à des données qui ne changeront probablement pas. Si ces doublons améliorent l'efficacité et les performances (et les deux sont requis), les "avantages" compenseraient probablement les "inconvénients"
Laiv
@GeraintAnderson Je veux dire, si vous avez besoin d'efficacité (qui est par définition une exigence non fonctionnelle), il existe des moyens de le faire. C'est-à-dire demander des pages de données au service d'inventaire (comme 10 éléments), prendre chaque page et utiliser cette page pour demander des données au service utilisateur et agréger à la fin. De cette façon, vous gardez vos limites tout en tirant parti du parallélisme des services indépendants. Même alors, ne vous embêtez pas tant que vous ne l'avez pas identifié comme un véritable goulot d'étranglement de l'application qui doit être résolu - attendre une demi-seconde supplémentaire sur un travail de nuit d'une seconde n'a d'importance pour personne.
Delioth
11

J'ai du mal à éviter la duplication des données ....

Selon l' ebook de Microsoft sur l'architecture des microservices , il n'y a rien de mal à la duplication des données. Fondamentalement, la duplication des données augmente le découplage entre les services et renforce donc leurs rôles en tant qu'autorité unique. Un passage pertinent:

Et enfin (et c'est là que la plupart des problèmes surviennent lors de la création de microservices), si votre microservice initial a besoin de données appartenant à l'origine à d'autres microservices, ne comptez pas sur des demandes synchrones pour ces données. Au lieu de cela, répliquez ou propagez ces données (uniquement les attributs dont vous avez besoin) dans la base de données du service initial en utilisant une cohérence éventuelle (généralement en utilisant des événements d'intégration ...

Maurits Moeys
la source
1
Je suis complètement en désaccord. Il est plus difficile à entretenir. Il vous fait implémenter des transactions entre microservices lorsque quelque chose doit être ajouté, mis à jour ou supprimé. Dans le cas où vous souhaitez éviter un seul point de défaillance, vous pouvez utiliser la demande ou tout autre type de mise en cache.
Alan Sereb
1
@AlanSereb C'est plus difficile à maintenir, mais le fait est que vous n'avez parfois pas d'autre choix. Par exemple, que faire si vous devez créer un FK entre des objets vivant dans deux bases de données? La seule façon de garantir la cohérence lors de l'exécution de requêtes dans une base de données locale consiste à avoir une réplication des données. Jetez un œil à: stackoverflow.com/a/4452586/2255491
David D.
Je suis d'accord. Une autre excellente approche consiste à emprunter la voie du sourcing d'événements. Et que toutes les mutations soient exécutées via le pipeline d'événements
Alan Sereb
4

une demande serait faite au service d'inventaire pour récupérer les détails de tous les articles dont la quantité est inférieure à 5. Cela retournerait une liste comprenant les ID utilisateur. Ensuite, une demande distincte serait effectuée auprès du service des utilisateurs pour obtenir le nom d'utilisateur et les coordonnées de la liste des ID utilisateur obtenus auprès du service d'inventaire.

Oui en effet.

Certes, dans un monolithe, vous pourriez avoir un modèle d'inventaire que vous recherchez pour les éléments pertinents, l'injecter dans un modèle utilisateur et obtenir les mêmes données.

Ou vous pouvez aller plus loin, si vous les avez dans la même base de données relationnelle et que vous écrivez SQL et que la base de données prendra la table d'inventaire et la table d'utilisateur, cela fait un peu de magie et vous obtenez les données que vous recherchez.

Quelle que soit la façon dont vous le faites, il y aura quelque part du code qui récupérera essentiellement une liste des identifiants utilisateur du système d'inventaire, les alimentera dans le système utilisateur et compilera une liste de données.

La question à laquelle vous devez répondre concerne les performances et la maintenance et les autres qualités "douces".

Le principal avantage des microservices est la mise à l'échelle. Si vous avez dix mille utilisateurs sur une machine et que c'est un peu lent, vous pouvez ajouter une autre machine et le système devient deux fois plus rapide. Ajoutez-en huit de plus et c'est dix fois plus rapide. (Mise à l' échelle linéaire est probablement optimiste, mais il est l'idéal et non que déraisonnable d'espérer.)

Et c'est par service . Si le système d'inventaire est le goulot d'étranglement, il est utilisé pour plus que des rapports sur les utilisateurs, vous pouvez ajouter plus de machines à ce service uniquement . Les machines peuvent également être spécialisées; ce service a besoin de beaucoup de mémoire, ce service fait des calculs lourds et a besoin de plus de cpu.

Si vous n'avez pas besoin de la mise à l'échelle, il y a un autre avantage des microservices: ils sont modulaires . Bien sûr, les applications monolithiques peuvent également être modulaires, et vous avez une base de données normalisée et ... mais dans la pratique, les murs entre les modules sont comme des murs en verre dans le meilleur des cas, et des lignes dans le sable dans le pire. Les microservices sont séparés par de l'acier massif.

Si votre système utilisateur prend littéralement feu, cela n'affectera en rien votre système d'inventaire. Vous ne pourrez pas imprimer de jolis rapports sur qui a stocké quoi, mais les clients pourront passer des commandes en toute sécurité en sachant que les articles en stock sont là.

Et vous ne dupliquez pas les données dans les microservices , pas plus que dans une base de données relationnelle (*). Dans une base de données relationnelle, vous pouvez faire une jointure , et l'équivalent est de fusionner les listes en code comme décrit.

Vous pouvez également ajouter une vue , l'équivalent est d'ajouter un nouveau service qui fait la fusion pour vous; cela aboutirait à trois demandes; un au nouveau service, puis ce service fait les deux d'origine. Les bases de données relationnelles ont des éléments sophistiqués qui optimisent les vues, qui doivent être implémentées au niveau du service. Vous ne l'obtenez pas "gratuitement".

La mise en cache est différente de la duplication de données en ce sens que si deux valeurs ne correspondent pas, vous savez laquelle est fausse. Il est souvent utilisé dans les microservices pour augmenter la disponibilité au détriment de la cohérence (théorème CAP). Étant donné que les bases de données relationnelles suppriment complètement la disponibilité sur l'autel de la cohérence, elles y sont moins courantes. Je dirais qu'il n'y a rien d'inhérent aux microservices qui facilite la mise en cache, mais dans la pratique, la mise en cache est une préoccupation principale et qui facilite la mise en cache dans les microservices .

(*) S'il est logique de dupliquer des données dans un essaim de microservices, cela aurait probablement du sens dans la base de données relationnelle équivalente à.

Odalrick
la source
3
J'ai vraiment aimé votre réponse jusqu'à ce que la partie «ne pas dupliquer les données dans les microservices». Je pense qu'il y a des cas où la duplication des données est la bonne approche. Il améliore la tolérance aux pannes et l'autonomie. Si le service utilisateur est tombé en panne, le service d'inventaire peut toujours afficher une liste des stocks bas avec qui les a stockés en dernier.
Peter Pompeii
1
@peterpompeii J'appellerais cela la mise en cache, pas la duplication de données. La duplication de données se produit lorsque vous avez deux emplacements à mettre à jour pour une donnée, la mise en cache lorsqu'il y a un emplacement et la propagation automatique vers les autres emplacements. J'ai aussi dit plus que relationnel. S'il est logique dans une base de données relationnelle de dupliquer des données, cela a du sens dans un microservice. Je pense que nous sommes d'accord et cette partie pourrait être plus claire, mais je n'ai qu'un téléphone pour le moment, donc je ne mettrai pas à jour le texte pour le moment.
Odalrick
@PeterPompeii J'espère que la section ajoutée sur la mise en cache répond à certaines de vos préoccupations.
Odalrick
1
@Odalrick, ce que vous avez décrit ressemble à de la réplication de données. La réplication et la mise en cache sont deux formes de duplication des données. La réplication, c'est quand une copie est garantie d'avoir toujours toutes les données nécessaires. La mise en cache est à la demande. La mise en cache peut manquer. La mise en cache pour la disponibilité n'a pas autant de sens que la mise en cache pour les performances. TL; DR si vous stockez une copie complète de quelque chose avec suffisamment de cohérence garantit que vous n'avez jamais besoin de vérifier les échecs, ce n'est pas un cache.
Brandon
1
@Brandon Une autre différence entre la réplication et la mise en cache est la façon dont vous savez quelles données sont erronées en cas de différence. La réplication définit certaines règles sur la façon de fusionner les données. La mise en cache est en revanche toujours : le cache est incorrect.
Odalrick