Microservices autonomes, files d'attente d'événements et découverte de services

15

J'ai lu beaucoup de choses sur les microservices ces derniers temps, et voici certaines des conclusions que j'ai obtenues jusqu'à présent (veuillez me corriger si je me trompe à un moment donné).

  1. L'architecture de micro-services va bien avec la conception pilotée par domaine. Habituellement, un EM représente un contexte limité.
  2. Si le micro-service A nécessite une fonctionnalité qui réside dans le micro-service B , mon modèle est probablement faux et A et B devraient en fait être un micro-service / BC.
  3. La communication synchrone entre les micro-services (requêtes HTTP directes) est mauvaise, car elle défie le but des micro-services et introduit le couplage entre les composants.
  4. Une communication asynchrone entre les services est souhaitable. Les services doivent publier des événements dans les files d'attente de messages, afin que d'autres services puissent s'abonner et traiter leur partie de l'événement, ou l'utiliser pour répliquer une partie des données nécessaires à leur contexte. De cette façon, les services peuvent traiter les demandes même si d'autres services sont en panne, ce qui ne serait pas le cas dans la communication synchrone.
  5. Si le micro-service A publie un événement, le micro-service B souscrit à cet événement et produit un nouvel événement comme résultat, le micro-service A ne doit pas être celui qui traite l'événement nouvellement créé, car ce serait une dépendance circulaire. Dans ce cas, nous devrions introduire un troisième micro-service ou combiner A et B dans le micro-service AB .
  6. Micro-service est en fait un terme trompeur. Nous devons viser les petits contextes, mais cela n'a pas besoin d'être le cas. Le terme ne doit pas être "micro-service", mais " assez grand pour faire le travail ".
  7. Les micro-services nous permettent d'introduire de nouvelles fonctionnalités avec plus de facilité et sans crainte de casser tout le système. Cela peut être fait en introduisant un nouveau service ou en refactorisant l'un des services existants.
  8. Chaque micro-service doit avoir son propre stockage de données. La réplication / duplication des données est un comportement souhaitable dans cette architecture.

Outre la confirmation de ma compréhension de cette architecture, mon autre partie de la question est principalement liée à la découverte de services. Si les services communiquent de manière asynchrone et utilisent une file d'attente d'événements centrale comme amazon SQS, cela signifie-t-il que la découverte de services n'a pas sa place dans une architecture comme celle-ci?

Les services ne doivent avoir aucune connaissance des autres services du système. Ils ne sont conscients que de leur contexte et des événements auxquels ils doivent publier ou auxquels ils doivent s'abonner?

Robert
la source

Réponses:

4

Vos conclusions semblent pour la plupart fondées et résument très bien la voie à suivre pour les microservices.

Je ne soutiendrais cependant pas pleinement 2, 5 et 8:

  • 2) Une simple dépendance ne doit pas conduire automatiquement à une fusion. Vous devez considérer la fréquence de ces appels dépendants ainsi que la fréquence des appels provenant d'autres services.

    Donc, si un microservice A nécessite très fréquemment des fonctionnalités dans le microservice B et que le microservice B est rarement nécessaire par d'autres microservices, vous devez contester la structure envisagée et demander s'il ne serait pas plus approprié de regrouper les deux microservices.

  • 5) bien sûr, vous devez éviter les cycles sans fin dans la gestion des messages.

    Mais l'ajout d'un intermédiaire ne l'empêchera pas: A pourrait lancer un message traité par C qui lance un message traité par B, qui lance un message traité par A et ici vous êtes pris au piège dans une boucle.

    Le problème ne peut pas être évalué uniquement en considérant le niveau de microservice: la question concerne vraiment le type et le contenu des messages qui pourraient conduire à un cycle. Le graphique qui modélise la distribution et le traitement des messages à travers les services doit donc être analysé dans son ensemble (en fait, cela peut être complexe, vous pouvez donc imaginer un microservice de surveillance qui détecte ces cycles et les brise).

  • 8) oui, chaque microservice doit avoir son stockage / base de données dédié.

    Un minimum de réplication est requis pour permettre aux services d'être indépendants. Cependant, je n'irais pas si loin pour dire que la réplication est souhaitée: elle doit être maintenue au minimum afin d'éviter le couplage caché via les processus de réplication.

    Les microservices concernent le couplage lâche. Cela peut parfois être réalisé plus efficacement en appelant un autre microservice pour récupérer les données associées, au lieu de répliquer les données.

Les deux dernières affirmations non numérotées sont trop larges pour être résolues ici. Je pense que votre suggestion est un bon point de départ, mais qu'elle dépend vraiment des exigences et des contraintes architecturales.

Christophe
la source
"Cela peut parfois être plus efficacement réalisé en appelant un autre microservice pour récupérer des données connexes, au lieu de répliquer des données". tant que cette requête ne représente pas une transaction / commande distribuée, sinon nous ne pouvons pas garantir l'atomicité de cette commande?
Robert
1
Il n'y a pas de solution parfaite ici: c'est un couplage et une encapsulation lâches ( microservices.io/patterns/data/database-per-service.html ) pour contrebalancer la facilité et la redondance ( microservices.io/patterns/data/event-driven-architecture .html ) dans le contexte de l'image globale ( microservices.io/patterns/microservices.html )
Christophe
3

Les micro-services consistent à découpler différents domaines de fonctionnalités. Chaque service peut être développé à un rythme différent, par une équipe différente, en utilisant une pile technologique différente. Cela crée une flexibilité organisationnelle. Le compromis est la complexité opérationnelle, où chaque service supplémentaire crée une chose supplémentaire qui doit être gérée dans un environnement opérationnel. Ainsi, le compromis fondamental entre monolithe et micro-service ne consiste pas à éviter les dépendances, il s'agit d'éviter le développement et le déploiement par étapes de verrouillage où tout doit être expédié en même temps, mais au prix d'avoir à expédier plus souvent car il y a plus de pièces mobiles.

Les services ne doivent avoir aucune connaissance des autres services du système. Ils ne sont conscients que de leur contexte et des événements auxquels ils doivent publier ou auxquels ils doivent s'abonner?

Le problème de l'évitement de la dépendance est un hareng rouge. Vous aurez toujours des dépendances entre des pièces de votre produit, et si elles sont dans un service distinct ou une partie du même code ne change pas le fait que les dépendances peuvent se briser. Ils peuvent tomber en panne au niveau opérationnel, car un serveur clé tombe en panne, et vous gérez cela grâce à des pratiques de redondance opérationnelle et de basculement. Ils peuvent également se rompre au niveau de l'intégration, car les pièces changent de manière incompatible, ce que vous détectez lors des tests d'intégration. Le brassage de code entre les services ne résout pas le problème des dépendances potentiellement rompues. Les solutions pour éviter les dépendances brisées sont la redondance opérationnelle et les tests d'intégration, qui n'ont rien à voir avec la taille de vos services.

Si les services communiquent de manière asynchrone et utilisent une file d'attente d'événements centrale comme amazon SQS, cela signifie-t-il que la découverte de services n'a pas sa place dans une telle architecture?

Pour répondre à cette question, répondez d'abord à celle-ci: pourquoi souhaitez-vous communiquer de manière asynchrone? Est-ce pour faciliter le développement indépendant de composants séparés? Est-ce pour améliorer la disponibilité opérationnelle d'un système 24/7? Disons que c'est ce dernier et que vous souhaitez utiliser des files d'attente pour répliquer les données vers des bases de données locales. Eh bien, maintenant, vos données peuvent être périmées. À un moment donné, ce sera trop périmé. Comment gérez-vous cela? De plus, comment garantissez-vous la disponibilité opérationnelle de la file d'attente, qui est un autre composant d'exécution? Et comment garantissez-vous la disponibilité de ces bases de données locales? Au lieu de gérer un cluster de base de données, vous en avez maintenant plusieurs. Votre équipe d'opérations peut-elle gérer cette charge de travail? Et vraiment, la complexité en vaut-elle la peine, alors que vos utilisateurs seraient peut-être plus heureux avec plus de fonctionnalités et quelques heures d'indisponibilité chaque mois si vous construisiez un monolithe simple?

Je pense que vous voyez mon point. La conception d'un système n'est pas une question de bien ou de mal, il s'agit de choisir parmi une grande variété de compromis. Tout ce qui ne va pas peut être vrai, et vice versa, si vous ne le voyez que dans le bon contexte. Votre contexte vous est propre, alors même si nous pouvons vous donner une réponse, ce ne sera pas la réponse. Rappelez-vous qui est votre public, quels sont ses besoins et le bon design se révélera.

Joeri Sebrechts
la source
2
  1. L'architecture de micro-services va bien avec la conception pilotée par domaine. Habituellement, un EM représente un contexte limité.

Être en désaccord. DDD a tendance à être très OO. une commande est livrée? Order.Deliver () alors que les micro-services auraient DeliveryService.Deliver (order)

  1. Si le micro-service A nécessite une fonctionnalité qui réside dans le micro-service B, mon modèle est probablement faux et A et B devraient en fait être un micro-service / BC.

En désaccord, vous devriez essayer de garder vos micro services micro. les diviser encore plus petits!

  1. La communication synchrone entre les micro-services (requêtes HTTP directes) est mauvaise, car elle défie le but des micro-services et introduit le couplage entre les composants.

Être en désaccord. les services ne devraient pas se soucier de qui les appelle et les appelants ne devraient pas se soucier que la logique est implémentée dans un microservice.

  1. Une communication asynchrone entre les services est souhaitable. Les services doivent publier des événements dans les files d'attente de messages, afin que d'autres services puissent s'abonner et traiter leur partie de l'événement, ou l'utiliser pour répliquer une partie des données nécessaires à leur contexte. De cette façon, les services peuvent traiter les demandes même si d'autres services sont en panne, ce qui ne serait pas le cas dans la communication synchrone.

Les files d'attente sont bonnes. Mais votre raisonnement est faux. la seule différence entre les réponses de synchronisation et l'async est que vous attendez la synchronisation. Vous pouvez implémenter des appels de style RPC avec des files d'attente et plusieurs travailleurs sans problème.

  1. Si le micro-service A publie un événement, le micro-service B souscrit à cet événement et produit un nouvel événement comme résultat, le micro-service A ne doit pas être celui qui traite l'événement nouvellement créé, car ce serait une dépendance circulaire. Dans ce cas, nous devrions introduire un troisième micro-service ou combiner A et B dans le micro-service AB.

Être en désaccord. Ce n'est pas une dépendance circulaire car vos micro-services ne sont pas couplés. Vous souhaitez également répondre aux renvois de sénarios, SendEmail, EmailFailed, SendAgain n'a pas besoin de 3 micro-services

  1. Micro-service est en fait un terme trompeur. Nous devons viser les petits contextes, mais cela n'a pas besoin d'être le cas. Le terme ne doit pas être "micro-service", mais "assez grand pour faire le travail".

Être en désaccord. Découvrez les nano-services.

  1. Les micro-services nous permettent d'introduire de nouvelles fonctionnalités avec plus de facilité et sans crainte de casser tout le système. Cela peut être fait en introduisant un nouveau service ou en refactorisant l'un des services existants.

Être en désaccord. Oui, vous obtenez le découplage, mais l'orchestration des micro-services peut être aussi intimidante que n'importe quel projet monolithique

  1. Chaque micro-service doit avoir son propre stockage de données. La réplication / duplication des données est un comportement souhaitable dans cette architecture.

Être en désaccord. Bien que vous ne deviez pas partager le stockage, vos micro-services devraient essayer d'être apatrides dans la mesure du possible. ne pas dupliquer les données sauf si elles sont en vol

Ewan
la source
1

Vos conclusions sont de bonnes règles d'or, mais pas universelles. Il y aura des cas où la meilleure option est d'enfreindre ces règles, même dans un projet entièrement nouveau. Dans certains cas, la communication synchrone est la meilleure option. Dans certains cas, il n'est pas bon de fusionner deux services en un même s'ils sont couplés par une communication synchrone.

Et à votre autre question, la découverte de service n'est pas requise pour la communication basée sur la file d'attente.

Orn Gudmundur
la source
0

Vous parlez juste de programmation orientée objet. Ou du moins, ce qu'il a été initialement conçu pour être: des morceaux indépendants de code en cours d'exécution communiquant entre eux à l'aide de messages.

Alan Kay a conçu la POO comme modelée sur des systèmes biologiques, où les cellules sont relativement indépendantes les unes des autres et communiquent simplement via des messages qui se branchent sur des interfaces externes sur d'autres cellules.

Alors pourquoi cessons-nous de le considérer comme OOP juste parce que tous les objets ne tournent pas sur le même ordinateur? Si quoi que ce soit, c'est encore plus orienté objet que s'ils sont sur le même ordinateur et une partie de la même application, car si tous les objets sont dans la même application, les développeurs cassent souvent la POO en utilisant des variables globales partagées par toutes les classes et y compris les mêmes en-têtes dans chaque fichier, etc. Lorsque tous les objets dépendent des mêmes éléments, ils ne sont pas aussi encapsulés que s'ils sont complètement indépendants les uns des autres, et l'encapsulation est tout l'intérêt de la POO.

Par exemple, à peu près tout ce qui est dit dans les autres réponses sont des déclarations de manuel sur la POO.

CommaToast
la source
0

Étant donné que je rencontre souvent une mauvaise compréhension d'un concept aussi important que le contexte délimité et le domaine principal, je voudrais en développer un peu.

J'ai trouvé extrêmement rentable de penser aux sous-domaines comme aux capacités commerciales. La capacité commerciale est quelque chose que fait votre organisation. C'est l'une de ses fonctions commerciales. Puisque notre objectif est l'alignement business-IT , je veux vraiment qu'ils aient une relation 1: 1 avec mes services techniques .

Donc, ce processus se résume à ce qui suit. Tout d'abord, je définis des capacités commerciales de niveau supérieur. Il devrait prendre la forme d'un nom et d'un verbe (ou d'une forme dérivée). Il existe généralement moins de 10 fonctionnalités métier. Puis j'immense plus profondément, en identifiant les capacités imbriquées. Et ainsi de suite, jusqu'à ce qu'il n'y ait rien à diviser. Les capacités que vous avez utilisées pour utiliser cette approche reflètent le domaine réel, la façon dont fonctionne votre organisation. Ces capacités seront naturellement couplées de manière lâche, donc si vous mappez vos services techniques à ces capacités, elles seront autonomes et pilotées par les événements. Ce processus est appelé cartographie des capacités commerciales , mais il existe d'autres moyens de trouver vos services, dont le plus important est probablement l' analyse de la chaîne de valeur .

Voici un exemple d'identification des limites de service à l'aide de cette approche.

Zapadlo
la source