Il y a 3 années · 11 minutes · Back

Microservices – Des architectures

Microservices. C’est une architecture dont on entend beaucoup parler, mais que se cache-t-il derrière ce terme ?

Avec une série de trois articles, nous allons tenter de découvrir ce qu’est une architecture microservices et ce qu’elle change par rapport à une architecture « classique ».

  • Le premier article s’intéressait tout d’abord aux concepts de ces architectures
  • Ce deuxième article illustrera ensuite des exemples possibles d’architectures microservices
  • Le troisième article s’attachera, quant à lui, aux pièges de ces architectures et aux pistes qui permettent de les éviter

Avant la présentation de ces architectures, intéressons nous rapidement à une application monolithique comme on en rencontre beaucoup actuellement. Voici un schéma présentant ce type d’application:

Capture d’écran 2015-03-09 à 14.44.12

Notre application est faite d’un seul package, toutes les couches communiquent entres elles via des appels de méthodes. Ce constat va nous servir de point de départ pour notre premier exemple d’architecture: les microservices en REST.

Microservices en REST

Comme expliqué dans les concepts, une architecture microservices est un système de services communicant entre eux.

Un des moyens les plus simples de faire communiquer ces services entre eux est de le faire à travers le protocole HTTP via une API REST. En reprenant l’exemple précédent, on peut imaginer isoler chaque partie métier de notre application pour la transformer en un service indépendant exposant sa propre interface. Les autres services du système communiqueront avec lui.

L’organisation de notre application ressemblera à ceci :

Capture d’écran 2015-03-09 à 14.44.23

Chacune des parties métier de notre application est devenue un service indépendant, ce qui présente plusieurs avantages:

  • Chaque service a une base de code plus petite, ce qui le rend plus lisible et facilite sa maintenance.
  • Chaque service étant indépendant du reste, il peut évoluer plus rapidement. Si le contrat d’interface est constant, les autres services ne seront pas impactés par les changements internes. De plus, toujours grâce à cette indépendance, il est possible d’écrire chaque service dans le langage qui correspond le mieux à l’équipe dédiée à son développement ou au besoin précis du service. Il est ainsi plus simple de focaliser les efforts de performance sur un service en particulier qui sera écrit en langage C, adopter l’isomorphisme javascript pour une interface web ou encore profiter de la richesse des bibliothèques java pour l’intégration avec le SI.
  • Chaque service peut travailler avec ses propres bases de données, du type qui correspond le mieux à son usage. Par exemple, il pourra utiliser une base NoSQL sans que les autres services soient obligés d’évoluer.

Un des gros avantages de cette architecture est de permettre aux services de scaler facilement et distinctement. Un service peu sollicité peut rester sur une instance unique tandis qu’un service devant supporter une charge importante peut multiplier ses instances d’exécutions de manière transparente.

Pour réaliser cela, il faut une méthode simple permettant aux services de se découvrir entre eux.

Chaque service doit connaitre les adresses de l’ensemble des services qu’il utilise. Une façon de faire serait d’indiquer l’adresse IP de chaque API dans la configuration du service. Cette pratique pose toutefois plusieurs problèmes:

  • Si l’adresse IP d’un service change, vous devrez changer l’intégralité des configurations utilisant ce service
  • Gérer les multiples instances d’un service avec une configuration par adresse IP est très compliqué. Cela oblige à maintenir manuellement l’inventaire des services utilisés

Etant donné que nous sommes dans un univers web, autant utiliser les moyens du web. La solution la plus immédiate consiste en la mise en place d’un loadbalancing qui va répartir la charge en entrée sur plusieurs instances du service. Quelle que soit l’implémentation technique retenue (IP, DNS, proxy, …), elle permet de scaler horizontalement, facilite la montée en version du service tout en offrant aux services consommateurs un point d’entrée constant.

Faisons un zoom sur le comportement d’un service fortement chargé où la communication est directe entre les services :

Capture d’écran 2015-03-09 à 14.44.28

Chacune des applications a été configurée pour accéder directement à un service en particulier. Une telle typologie, bien que simple à mettre en œuvre présente plusieurs inconvénients. D’une part il est impossible d’ajouter une instance d’un service consommé et d’autre part la mise à jour du service entraine nécessairement une rupture dans la continuité de service.

L’utilisation d’un loadbalancer pour supporter la montée en charge n’est pas spécifique aux architectures microservices mais il permet d’orchestrer efficacement la montée en version. Le nouveau service est démarré, le loadbalancer redirige les requêtes vers le nouveau service puis l’ancien service peut être décommissionné.

Maintenant si nous glissons un loadbalancer dans le système, il est facile d’ajouter de nouvelles instances de notre service (vert) sans bouleverser le système :

Capture d’écran 2015-03-09 à 14.44.32

Le loadbalancer est une bonne solution pour faciliter la scalabilité de votre système. Néanmoins, il faut être conscient que cela ajoute un élément actif sur l’acheminement de la requête et donc une latence supplémentaire ou une potentielle panne. Cet élément devient donc critique. Il s’avère être une solution simple pour quelques services mais peut s’avérer complexe à une échelle plus importante.

Comme nous venons de le voir, ce type d’architecture permet de mettre en place simplement des microservices grâce à un système de communication couramment utilisé, même dans des applications monolithiques. Néanmoins ce système révèle plusieurs problèmes:

  • Les appels REST sont synchrones, si un service ralentit, l’ensemble du système s’en trouve impacté
  • Certains appels REST ne sont pas idempotents (principalement POST et PUT) et ne peuvent être rejoués plus tard au premier échec
  • La multiplication des services peut entraîner un effet « spaghetti » entre les liens de communication
  • Transposer une application monolithique en microservices en remplaçant un appel de méthode par son équivalent en RPC (REST ou autre) limite les performances globales du système.

Résumer les services REST aux seuls appels synchrones serait un raccourci maladroit. Rien n’interdit en effet de concevoir une architecture reposant sur des messages asynchrones tout en utilisant le protocole HTTP. Certes ce dernier est synchrone par définition mais il est tout à fait possible qu’un service consomme un autre service en communicant une adresse de callback, laquelle sera appelée lorsque le traitement sera terminé. Nous rencontrons fréquemment cette séquence d’échanges dans les protocoles SSO par exemple. Le terme d’asynchronisme peut ainsi avoir une signification différente selon que l’on se place au niveau du protocole d’échange ou au niveau de l’orchestration des échanges.

Pour palier aux différents problèmes évoqués précédemment, un autre système de communication existe : la communication par bus de messages.

Microservices à travers un bus

La communication par bus de messages est fortement poussée dans les architectures microservices. Elle apporte une réelle souplesse que nous allons détailler par la suite.

Néanmoins, ce type de communication change complètement la manière de penser les applications. Il faut être conscient de ce fait avant de se lancer dans la conception d’une telle architecture.

Comme exposé précédemment, la communication par services REST peut devenir une faiblesse lorsque le nombre de liens se multiplie. Dans la communication par messages, les liens entre services sont remplacés par un bus central :

Capture d’écran 2015-03-09 à 14.44.44

Chaque service envoie des messages sur le bus qui seront consommés ensuite par d’autres services. On remarque tout de suite un avantage dans les échanges: chaque service ne connait que le bus de messages comme intermédiaire. Les liens directs entre services sont coupés. Naturellement, chaque service doit connaitre la typologie des messages qu’il souhaite utiliser.

La responsabilité d’un bus est volontairement limitée: transmettre les messages. Suivre cette approche permet de réduire au maximum l’impact du bus de communication sur le métier. Il s’agit d’un composant d’infrastructure sans intelligence particulière. Cette intelligence business est concentrée aux extrémités, dans les (micro-)services. Les critères de sélection d’une solution technique sont ainsi simplifiés : le bus doit faire peu de choses mais bien. Parmi ces critères retenons la capacité de débit, la garantie d’acheminement, la latence ou la typologie réseau.

Pour qu’un service reçoive des messages, il doit simplement écouter sur le bus ceux qui l’intéressent. Les services sont ainsi réellement isolés du reste du système. Leurs seuls liens vers l’extérieur étant la typologie des messages (reçus ou émis), ainsi que le bus.

L’utilisation d’un bus de messages induit un nouveau concept : tout ce qui se passe dans le système est asynchrone. En effet, une fois un message envoyé sur le bus, il n’y a aucune garantie qu’il sera lu et surtout, quand il sera lu.

Ceci oblige à penser l’architecture de manière totalement asynchrone, ce qui peut être déroutant au départ. Néanmoins, cet asynchronisme présente plusieurs avantages :

  • Le système devient résistant à la lenteur. Une fois le message envoyé, le service n’attend pas de réponse immédiate. Si le service répondant devient lent, l’appelant n’est pas impacté
  • Le système devient tolérant à la panne. Si un service tombe, tous les messages qui lui sont destinés sont gardés dans le bus. Il pourra reprendre le travail une fois redémarré, sans perte.
  • Le système devient facilement scalable. N’importe qui peut lire dans le bus, qu’il y ait une ou dix instances du même service ne change rien pour le bus et cela répartit la charge entre chaque instance

Ce type d’architecture permet de réellement découpler les services et de les faire évoluer de manière totalement indépendante. Tant que la typologie des messages ne change pas, l’évolution des services sera transparente pour le système.

Comme vous l’avez sans doute remarquer, le point sensible des architectures avec communication par messages est le bus lui même. Il devient le goulot d’étranglement du système.

Heureusement, aujourd’hui, les technologies de bus supportent particulièrement bien la charge, permettent de scaler le bus facilement et si besoin de rejouer les messages. Le rejeu d’anciens messages conduit vers le principe d’event sourcing.

Les bus se doivent également d’être des « dumb pipe ». Autrement dit, un bon bus ne porte aucune intelligence de routage. Il reçoit des messages que d’autres services viennent lire. Le bus est un élément technique du système, pas un élément fonctionnel. C’est un point essentiel qui permet d’éviter d’avoir des bus très complexes contenant des tables de routages encore plus complexes.

Un autre point également très important dans ce type d’architecture est le monitoring. L’ensemble étant totalement asynchrone et découplé, un service peut tomber sans que cela soit visible immédiatement. Les autres services continueront d’envoyer leurs messages sans ralentissement visible. Il est donc primordial de penser à un bon système de monitoring. Que les données collectées soient business ou techniques, il est impératif de savoir ce qui se passe dans le système. Mettre en place des dashboards simples et visuels permettront de détecter rapidement les problèmes.

Conclusion

Nous venons de voir deux types d’architectures microservices. La première avec communication par service REST est certainement la plus simple à mettre en oeuvre. Elle est efficace lorsqu’il s’agit de migrer depuis une application monolithique.

La deuxième architecture avec le bus de messages est la plus intéressante. L’asynchronisme rend plus robuste et plus tolérant le système. Le bus permet de scaler horizontalement tout type de services simplement et efficacement.

Il est par ailleurs tout à fait envisageable de mixer les deux types d’architecture afin d’obtenir une architecture hybride. Ceci peut par exemple être envisagé lors d’une migration progressive vers du tout asynchrone.

Ces architectures sont surtout utilisées dans des environnements complexes devant absorber une charge importante.

Le lot de nouveautés des microservices apporte également de nouvelles problématiques : sécurité du bus de messages, gestion de l’asynchronisme, débuggage de systèmes complexes. Le monitoring de ces systèmes est un élément très important à prendre en compte. Sans un bon monitoring, les systèmes complexes peuvent devenir un enfer à gérer en production.

Heureusement, de nouveaux outils sont apparus pour aider à la mise en place d’une architecture microservices. Des frameworks comme vert.X avec un bus intégré ou encore Spring Boot permettent de créer rapidement de nouveaux services.

L’orchestration du système est également un point essentiel. Le nombre de services se multipliant, il devient important d’automatiser les déploiements et la gestion de l’ensemble. Là aussi, des outils font leur apparition comme Marathon et Mesos. Les microservices se marient idéalement avec Docker.

Dans notre prochain article, nous verrons plus en détails les pièges possibles des microservices et comment les éviter.

Références

http://martinfowler.com/articles/microservices.html

http://www.infoq.com/fr/news/2015/02/microservices-sharing-code

https://blog.yourkarma.com/building-microservices-at-karma

http://www.javaworld.com/article/2863409/soa/why-2015-will-be-the-year-of-microservices.html

http://www.infoq.com/news/2014/05/microservices

18 réflexions au sujet de « Microservices – Des architectures »

  1. Publié par greve, Il y a 3 années

    Pour résumé simplement du boulshit marketing pour parler des principes SOA, d’ESB, d’API Management et de gestion classique de charge en mettant en place un load balanceur qui existent tous depuis des années.

  2. Publié par Romain Niveau, Il y a 3 années

    Bonjour,

    Je vous invite à lire le premier article sur la série des microservices qui revient sur les concepts.
    http://blog.xebia.fr/2015/03/02/microservices-les-concepts/

    Il explique en quoi les microservices sont différents de la SOA.
    Les microservices sont une nouvelle forme d’architecture qui provient de la SOA bien entendu mais qui a tiré les conséquences des défauts de cette dernière.
    Vous avez raison et nous l’avons indiqué dans l’article, le loadbalancing n’a rien de nouveau. Nous expliquons juste avec un cas concret comment scaler facilement des services grâce à ce système.

    Enfin, aucun ESB n’est présent dans les microservices et c’est là un gros point de différence avec la SOA. Les bus de messages des microservices sont des dumps pipes, ne portant aucune intelligence afin d’éviter justement les écueils des ESB avec leur table de routage compliquée.

    Je vous invite à lire également les articles placés en référence qui peuvent apporter un éclairage différent sur cette architecture.

  3. Publié par Anas, Il y a 3 années

    Mis à part l’éclatement des couches des applications, il n’y pas de nouveautés fondamentale par rapport à la SOA classique.

    J’ai quelques remarques concernant certaines affirmations:

    « […] L’utilisation d’un bus de messages induit un nouveau concept : tout ce qui se passe dans le système est asynchrone.[…] »

    Heuh ! non … le concept n’est pas si nouveau que ça. On fait de l’asynchronisme dans les bus depuis longtemps (depuis les MOM et les EAI ancètres du bus).

    « […] Ce type d’architecture permet de réellement découpler les services et de les faire évoluer de manière totalement indépendante. Tant que la typologie des messages ne change pas, l’évolution des services sera transparente pour le système. […] »

    Il y a confusion entre découplage dynamique et découplage statique:

    Le découplage dynamique consiste a rendre le consommateur et le fournisseur le plus indépendant à l’exécution. L’asynchronisme apporte du découplage dynamique car à l’exécution, le consommateur n’est plus obligé d’attendre la réponse du fournisseur.

    Le découplage statique consiste à rendre consommateurs et fournisseurs les plus indépendants à la conception.

    Le découplage dynamique peut se faire avec un couplage statique fort (… à éviter) tandis que le découplage statique peut (et doit) se faire indépendamment du synchronisme ou de l’asynchronisme du service.

    Les deux formes de découplage doivent être « découplées » car le contexte permet rarement les deux à la fois. Au niveau des ressources qui définissent les structures de données métier échangées, les concepts de synchronisme/asynchronisme ne doivent pas transparaître.

  4. Publié par Jérome Doucet, Il y a 3 années

    Je vous rappelle que cet article fait partie d’une série d’article portant sur les microservices. Celui-ci ne traite que des pistes de mise en oeuvre.

    Si vous désirez en savoir plus sur les concepts, cet article : http://blog.xebia.fr/2015/03/02/microservices-les-concepts/ sera plus approprié.

  5. Publié par Romain Niveau, Il y a 3 années

    @Anas: Effectivement, cet article est très intéressant, nous l’avons d’ailleurs placé en premier dans la liste de nos références.
    Nos autres références apportent également un angle différent sur les microservices ou leurs mise en oeuvre.

  6. Publié par Gregory, Il y a 3 années

    Bonjour,
    J’aimerai si possible que vous m’éclaircissiezsur un point.
    J’ai du mal à saisir le fonctionnement du bus que vous présentez ici, ce n’est pas du tout un ESB ?
    Si je comprends bien (corrigez-moi si je me trompe) :

    • Un ESB permet la communication entre plusieurs applications mais il est intelligent, il a de nombreuses responsabilités (transformation et transmission de messages, routage, gouvernance, orchestration, etc… j’en passe)
    • Le bus que présentez est « bête » (ce n’est qu’une image), il a pour seul rôle : stocker les messages qui lui sont envoyés en attendant que les services qui sont connectés à lui les récupère, en gros il ne fait rien c’est juste un canal qui attend

    Je débute dans le domaine, je voulais me lancer dans le microservices et l’avais commencé à étudier les ESB pensant partir sur un bus, sauf qu’au vu de vos commentaires précédents l’ESB ,n’est pas du tout le bus que vous présentez. Il s’agirait donc d’implémenter un bus tout simple ?

    Dans l’attente d’une éventuelle réponse,
    Cordialement,

  7. Publié par Romain Niveau, Il y a 3 années

    Bonjour Gregory,

    Vous avez parfaitement compris la différence entre l’ESB et le bus « bête » que nous présentons.

    L’un porte beaucoup de complexité et devient un point problématique du système quand l’autre n’est qu’un moyen de stocker les communications entre les services et ne porte aucune intelligence de routing et autre.

    Concernant l’implémentation, ce n’est bien sur pas à vous de faire ce bus (sauf si vous voulez vous faire plaisir). Il existe plusieurs outils capable de faire ce travail correctement. Chacun travaillant avec des protocoles et concepts différents.

    Pour faire du jms en Java, vous avez hornetQ.
    Pour faire du amqp en Java et autres langages (js), rabbitmq est une possibilité.
    Enfin, un peu plus complexe mais intéressant (surtout si vous voulez partir sur de l’event sourcing par ex), kafka est un autre bus (propulser par linkedin)

  8. Publié par Thomas Auffredou, Il y a 3 années

    Bonjour,

    Vous avez saisi l’essentiel, les responsabilités du bus sont de transmettre les messages et, selon les choix d’architecture, de prévenir de la perte de messages.
    Limiter ainsi les responsabilités a plusieurs avantages immédiats :
    – les produits étant plus simples, il existe un large choix de solutions techniques
    – les bus sont capables de traiter des débits importants de messages
    – la mise en œuvre est simple

  9. Publié par Gregory, Il y a 3 années

    Bonjour,
    Je vous remercie infiniement pour les précisions que vous apportez ainsi que la réponse très rapide.
    Je pensais bien évidemment pour l’implémentation partir sur des outils existant, mes recherches sur les MOM me redirigeaient que sur du JMS, après plus de recherche j’ai trouvé l’AMQP qui semble être une excellente alternative pour l’hétérogeineté (http://blog.xebia.fr/2010/02/23/amqp-une-alternative-a-jms/ => article qui m’a permis de découvrir et comprendre l’AMQP, décidemment ce blog me sauve).
    RabbitMQ semble être une très bonne solution, il propose un gros pannel de clients dans de nombreux langages développés par la communauté, les autres semblent un peu moins complet peut être que je me trompe.
    Sur wikipédia on a une bonne liste de MOM et plus précisement en AMQP (liste de Broker et de Client). Pour ceux qui débutent un peu dans le domaine comme moi je conseils d’aller faire un tour pour comparer les solutions.

    En ce qui concerne le développement en REST, le but est de développer pleins de petites API REST totalement indépendantes les unes des autres dans leurs développements ? Ensuite, une fois tous les services développés et lancés, ils pourront s’appeller les uns avec les autres.

    Je vous remercie encore pour vos réponse, je me suis lancé dans un gros travail de recherche et de comparaison avant de mettre en place mes microservices, et c’est encore un peu flou pour moi.

    Cordialement,

  10. Publié par Roger, Il y a 2 années

    Hello,
    I have read a couple of articles on Microservices (including this one :-)) but have some questions:
    1) How about the presentation layer. Is this included within the service?
    2) Data mapping from API message towards internal data is done by the service itself?
    3) How about business flows that must wait on a step to be completed? Are processes part of microservice or a « layer » on top of the service? Or is the process internal to the service?

    Regards
    Roger

  11. Publié par Romeo SAVU, Il y a 2 années

    Bonjour,

    QUID d’implémentation microservices en REST (implémentation de la logique métier) à travers :
    1) Une plateforme d’API Management
    2) Les clients Web, mobile

    Pourriez-vous en donner votre avis, merci.

    Cordialement,

  12. Publié par Thomas Auffredou, Il y a 2 années

    Bonjour,

    Les API gateway permettent l’agrégation de services services internes pour exposer une API limitant le nombre d’appels serveur.
    Concernant la consommation des services par des clients web ou mobile, l’utilisation d’un « backend for frontend » est une bonne pratique répandue, à la fois pour simplifier la gestion de la sécurité mais également pour assurer la stabilité de l’API.

    Vos services étant exposés sur internet, ils seront sécurisés et l’accès sera probablement restreint pour certains d’entre eux. L’utilisation d’une plateforme API management offre les outils pour gérer l’authentification ainsi que des informations sur la consommation de vos API. A l’inverse, la consommation directe des services oblige à gérer à chaque fois les mêmes problématiques techniques, sans valeur métier. OAuth, par exemple, permet cependant la propagation de l’authentification aux services.

    Selon la complexité du système et des exigences de sécurité, l’implémentation des services s’avère alors plus simple, une partie des contraintes techniques étant portées par la plateforme d’API management.

    Cordialement

  13. Publié par DAI, Il y a 2 années

    @Romain:

    Je pense que vous confondez brokers et bus..
    Un bus n’est pas un broker
    et un broker n’est pas un bus

    Je comprends que pour vour « bus bête »= »broker »

  14. Publié par dieng, Il y a 12 mois

    Bonjour,
    Merci pour cet article et commentaires intéressantes. J’ai vraiment appris beaucoup de choses. Merci !
    Est-ce qu’il y’a une différence entre BUS et Middleware ?

    Merci

  15. Publié par Mohamed, Il y a 10 mois

    Bonjour,

    merci pour cet article très intéressant!
    j’ai une question, comment « une archi microservices peut se marier idéalement avec Docker? »

  16. Publié par Thomas Auffredou, Il y a 10 mois

    Bonjour,

    Docker épouse parfaitement les architectures microservices, ce use case est d’ailleurs souvent mis en avant.
    Quelques points de synergie :
    – Une des promesses des microservices est d’offrir au développeur le choix du langage. L’utilisation de conteneurs favorise grandement la gestion de stacks techniques éclectiques.
    – Docker propose un certain nombre d’outils pour déployer des services de façon continue : API, évenements, …
    – Sur le poste dev, il est très pratique de pouvoir déployer l’ensemble des services grâce à docker-compose

    Cependant, il devient vite nécessaire de mettre en place un orchestrateur pour répondre aux problématiques de haute disponibilité ou de répartition de charge.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *