Les Architectures Micro-Services (AMS) permettent de construire et d’adapter un système d’information en permanence. En divisant les responsabilités, tout en limitant le périmètre de chaque service, ce principe permet de construire une solution logicielle simple, résiliante et capable de s’adapter à la charge. Voyons comment le monde des jeux vidéos nous a inspiré, en revenant sur les principes des jeux de stratégie temps réel.
L’idée m’est venue en effectuant un rangement le week-end dernier. Je tombe sur cette vieille boîte d’un jeu vidéo, que les moins de 20 ans ne doivent pas connaître : Warcraft II, Tides of Darkness. Le jeu date de 1996, c’était un jeu de stratégie temps réel simple et addictif. Vous dirigez différentes unités dans ce jeu. Du petit paysan au dragon, en passant par les archers, les chevaliers, des bateaux, bref des unités autonomes, que vous dirigez. Chaque unité ne fait que quelques actions, mais l’ensemble vous permet de construire votre ville, et d’aller chercher des ressources à l’extérieur.
Il y a ce gros château, votre place forte. Et ensuite un ensemble de lieux, avec des unités qui se baladent, vont chercher des ressources, et sont presque autonomes.
Ressources limitées, univers à explorer, et des unités spécialisées…
Le projet principal, le château
Les projets informatiques sont en général envisagés comme une seule brique livrable, que l’équipe soit constituée de 2 ou de 25 développeurs. C’est l’approche naturelle, qui semble la plus simple, et qui permet en principe, de simplifier la partie production, et les livraisons.
Premier point intéressant : les projets de ce type tendent à grossir, à devenir de plus en plus riches, et aussi de plus en plus complexes.
En étant un peu critique, nous avons été éduqué pour construire une seule brique logicielle, avec le secret espoir que ce logiciel soit capable de tout faire. De l’interface Web à la gestion en mode batch, tout en passant par des systèmes de gestion métiers… il est plus simple à priori de regrouper différents services.
Le souci c’est que les responsabilités et les besoins de l’application doivent aussi pouvoir évoluer. Alors on ajoute un module d’envoi d’email, un autre module de recherche full-text pour le site, et une autre version du site Web…
N’y-a-t-il pas un souci d’évolution, de capacité à livrer rapidement et surtout, de complexité ?
Au final, nous avons construit un bon gros projet, qui correspond exactement à l’équipe en charge de son développement.
On est pas des Orcs
Une caractéristique des architectures logicielles, c’est qu’elles sont profondément influencées par l’humain, et surtout, par les relations entre les équipes. Les projets tendent à s’organiser comme les relations entre les équipes. Pire, les projets calquent souvent l’organisation de l’entreprise, les bonnes ou les moins bonnes relations entre les équipes et les différents départements.
Marvin Conway en 1968 dit :
» organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations (source) «
L’un des points novateurs de l’approche micro-services, est tout d’abord la remise en question du pattern « une équipe = un projet ».
L’introduction de micro-services va provoquer une petite remise en question de « qui fait quoi ». Vous verrez qu’un ou deux développeurs, accompagnés d’un chef de projet ou d’une personne de la maîtrise d’ouvrage… suffisent à livrer quelque chose. Plus petit, donc plus simple, et surtout beaucoup plus Agile.
Deuxième observation : il est intéressant de mettre en place un système de gestion du code source démocratique et décentralisé. Ceci permettra à tout le monde de proposer des pull-requests. Si vous avez aussi la possibilité d’introduire de l’intégration continue, voire de la mise en production continue, c’est encore mieux. Il apparaît donc que les micro-services s’accompagnent aussi de pratiques de déploiement continue.
Une plate-forme de type PaaS semble adaptée, mais globalement, n’importe quelle solution basée sur du Cloud computing fera l’affaire.
Les ressources
Repensez à Clash of Clans ou Warcraft. Ces petits paysans vont couper des arbres et chercher du minerai. De quoi votre micro-service a-t-il besoin ? D’un gestionnaire de code source, d’un système de build, d’un outil de tests, un outil de déploiement et enfin, de ressources informatiques (CPU, mémoire, réseau) pour fonctionner.
A noter que la vision se doit d’être la plus simple techniquement. Pas forcément besoin d’un serveur d’application ou d’un conteneur de Servlet. Laissez les développeurs prendre et assumer des décisions. Si Node.JS ou Go répondent au problème… pourquoi pas ?
Imaginez chaque micro-service comme autant de maisons ou d’ateliers, autour de votre château fort.
Construire pour durer ?
Je pense qu’il est plus pertinent de parler dès le départ du moment où le projet sera mort. Ainsi, pas de fausses promesses, et pas trop d’espoirs. Soyons réaliste, une majorité des projets informatiques ne passent pas les 5 ans. Autant prendre cela comme un fait, et se mettre dans une posture pour construire, entretenir et tuer, dès lors que le projet n’a plus d’intérêts. C’est là que les micro-services deviennent intéressants. Vous allez pouvoir reprendre, améliorer ou tuer chaque partie de votre infrastructure.
Si vous vous interrogez sur la durée de vie d’un logiciel, je vous invite à découvrir les 8 lois de Lehman’s :
- (1974) « Continuing Change » — an E-type system must be continually adapted or it becomes progressively less satisfactory[14]
- (1974) « Increasing Complexity » — as an E-type system evolves, its complexity increases unless work is done to maintain or reduce it[14]
- (1974) « Self Regulation » — E-type system evolution processes are self-regulating with the distribution of product and process measures close to normal[14]
- (1978) « Conservation of Organisational Stability (invariant work rate) » – the average effective global activity rate in an evolving E-type system is invariant over the product’s lifetime[14]
- (1978) « Conservation of Familiarity » — as an E-type system evolves, all associated with it, developers, sales personnel and users, for example, must maintain mastery of its content and behaviour to achieve satisfactory evolution. Excessive growth diminishes that mastery. Hence the average incremental growth remains invariant as the system evolves.[14]
- (1991) « Continuing Growth » — the functional content of an E-type system must be continually increased to maintain user satisfaction over its lifetime
- (1996) « Declining Quality » — the quality of an E-type system will appear to be declining unless it is rigorously maintained and adapted to operational environment changes
- (1996) « Feedback System » (first stated 1974, formalised as law 1996) — E-type evolution processes constitute multi-level, multi-loop, multi-agent feedback systems and must be treated as such to achieve significant improvement over any reasonable base
Au global la solution sera donc comme ce village, avec différents bâtiments, que vous faîtes évoluer, disparaître ou croître.
Qu’est-ce qu’un projet « Château » ?
Un logiciel informatique monolithique est constitué d’un seul et unique livrable. Il fonctionne de façon autonome, ou dans un serveur d’application. Il arrive parfois que le code soit déployé sur plusieurs serveurs physiques, afin de pouvoir gérer une meilleur disponibilité, ou pour tenir la charge. Du côté du code source, un seul entrepôt de code, parfois divisé en petits modules, permet de construire le logiciel.
Souvent, il faut plusieurs minutes pour compiler le projet. Très souvent, les mises à jour et les installations sont effectuées par une autre équipe de bâtisseur, appelé « La Prod ». C’est la vie de beaucoup de projets d’application de gestion dans le monde de la Banque.
Ne pas détruire le patrimoine (legacy) et garder son gros château
L’idée de base de l’approche micro-services, selon moi, n’est pas forcément de remettre en question ce projet, ce gros château. C’est plutôt d’envisager les évolutions ou de prévoir une autre façon d’apporter de nouvelles fonctions à votre projet principal. S’il est possible de déplacer ce château sur du CloudComputing, tant mieux. Sinon ce n’est pas grave, il va falloir envisager d’ouvrir une brèche ou deux pour que des micro-services viennent chercher de la donnée, et rendre de nouveaux services.
L’approche micro-services challenge aussi les solutions techniques. Tant qu’il est possible de communiquer, que les échanges se font de façon asynchrone, que les échanges concernent des messages, alors vous pouvez y aller.
Différentes composants, et donc différents services
L’observation de chaque projet permet de distinguer des composants. Un ou plusieurs composants fournissent un service. Et c’est là, qu’il devient intéressant d’introduire cette notion de micro-services. C’est d’abord un produit complet, pas forcément un projet.
Pour terminer, essayons de lister quelques caractéristiques d’un micro-service :
- une application autonome avec son environnement d’exécution, son propre cycle de vie
- un seul livrable, à partir d’un seul code source
- connecté sur le réseau
- expose une API Web type REST
- embarque ses propres solutions techniques
- intègre l’ensemble des couches logicielles (de l’UI à la persistence)
- sous la responsabilité d’une équipe réduite, pluri-disciplinaire (dev, ops, qa, gestion projet)
- industrialisé pour se déployer automatiquement dès lors que les tests unitaires et d’intégrations fonctionnent
- facile à remplacer ou à faire évoluer, sans changement de contrat au niveau API
Une solution architecturée en micro-services c’est :
- un ensemble de micro-services autonomes
- une communication via HTTP
- pas de bus intelligent
- éventuellement une solution de messaging type RabbitMQ pour de l’asynchronisme
- idéalement hébergé sur du Cloud computing, type Paas ou Saas.
Contrairement à une solution basée sur un ESB, les échanges entre les services doivent se faire sur des canaux pauvres, sans médiation ou transformation. On recherchera la simplicité et donc, les solutions type ESB n’ont pas leur place (à mon avis) dans une approche micro-services. On parlera sinon plus d’une architecture orientée service, où le bus est partie intégrante de la solution.
Quel est la taille d’un micro-service ?
Elle correspond d’abord à une équipe de développeur, capable de construire de A à Z ce produit. L’équipe doit être en charge de la production, et responsable de la maintenance de cette brique. Idéalement une petite équipe avec plusieurs métiers. Au delà, tout le monde n’interviendra pas sur toutes les parties, et il est peut-être nécessaire de revoir l’architecture.
Responsable ne veut pas dire propriétaire. Il est intéressant de prévoir l’accès au code, le support des Pull-Requests et pourquoi pas, la possibilité de livre. Dans ce cas, il faut accompagner la solution d’une bonne partie DevOps, de la mise en place de l’intégration continue, et enfin, du déploiement continu.
Essayez de voir si votre produit correspond à ces critères :
- le temps de build du produit ne dépasse pas la minute
- le packaging avec les tests prennent moins de 3 minutes
- le temps de mise en prod ne dépasse pas les 10 minutes
- tu n’as pas besoin de demander la permission
- tu es capable de fixer un bug en prod
C’est exactement ce que nous nous imposons, et c’est aussi ce que j’impose sur les projets auxquels je contribue (CFP de DevoxxFR).
Et comment faire avec mon architecture monolithique ?
Lorsque l’on arrive sur un vieux projet, il est parfois plus simple de ne pas toucher l’existant. Après tout, même si c’est un projet complexe, il fonctionne et il est encore en vie. Une autre approche c’est l‘approche Botox. Les micro-services sont des composants simples, autonomes, que vous pouvez déployer sur une infrastructure existante.
La tendance est de vouloir détruire les systèmes existants, alors qu’au contraire, je pense qu’ils peuvent être boostés simplement, sans trop y toucher.
La mise en place d’un moteur de recherche peut s’effectuer sous la forme d’un micro-service autonome, intégré uniquement avec quelques pages HTML dans l’ancienne application.
L’envoi d’emails en mode batch peut s’effectuer avec un service qui se branche sur la base de données relationnelle, sans passer par les multi-couches Pampers de la grosse application J2EE des années 2000… Le challenge est de s’adapter, pas forcément de tout dynamiter
Ce faisant, vous aurez l’impression d’être ces petits paysans dans Warcraft, qui construisent différents bâtiments. Chacun de ces bâtiments répond à un rôle bien précis.
Après tout, notre métier consiste peut-être à construire des châteaux, pour avoir un jour une ruine à visiter.
Références:
- Définition des Microservices selon Martin Fowler
- Présentation Parleys Microservices on the JVM : A practical overview
- TolerantReader, pattern M.Fowler 2011
- Pattern Circuit Breaker avec Akka
Très intéressant, c’est justement un sujet qui me trotte dans la tête régulièrement ces temps-ci.
Personnellement je suis très attiré par les architectures micro-services, mais je sens pas mal de collègues réticents, notamment dès qu’on aborde les fameuses illusions des systèmes distribués (http://en.wikipedia.org/wiki/Fallacies_of_distributed_computing).
Que pensez vous du lien entre les micro-services et les solution d’intégration (EAI)? Je n’ose pas vraiment parler d’ESB car on l’associe encore (trop à mon sens) avec SOA, mais au final si on crée progressivement de plus en plus de micro-services, les besoins en communication entre « applications » grandissent progressivement et donc de fait la complexité de la topologie.
Donc à mon sens la seule approche censée consiste à mettre une couche de médiation entre les différents micro-services, qui se sert potentiellement d’un store central pour stocker/accéder aux configurations (e.g., où trouver une instance du service x ou y). Laisser les micro-services communiquer directement entre eux (donc créer des liens forts entre eux) me semble au bas mot dangereux, par exemple en cas de mise à jour, etc.
Par contre je pense que la couche de médiation doit être la plus bête possible et exclure toute logique business (et je crois que c’est le travers principal des implémentations d’ESB..).
Un autre aspect qui a tendance à inquiéter les gens autour de moi quand on aborde le sujet, ce sont les performances. J’imagine bien que le but des micro-services n’est pas de découper jusqu’à en arriver à des « nano »-services, mais n’empêche qu’une découpe d’une application monolithique en n applications plus légères implique de fait une communication plus lente entre les différents composants. Peut être que pour composer une vue intéressante pour le business il faudra faire appel à n micro-services, qui prendront chacun un peu de temps pour répondre, etc. Que pensez-vous de cet aspect là?
Un dernier point auquel je pense c’est le mode de déploiement de micro-services. Je crois que si on commence à déployer des micro-services, on a aussi tout intérêt à investir dans la containerization (je ne sais pas si le terme a déjà été traduit par l’académie française mais je ne suis pas fan ~~) et donc des choses du style Docker. Le fait de pouvoir déployer (très) rapidement une application voir de la remplacer par la version n-1 en cas de problème est très intéressant. Aussi, la légèreté des conteneurs (l’impact insignifiant au niveau stockage de déployer 1 ou 10 conteneurs basés sur une image donnée) est essentielle pour limiter l’impact des micro-services sur l’infrastructure et potentiellement limiter le côté administratif..
Au final (j’ai peut être tort), mais j’ai tendance à voir un lien fort entre les choses suivantes:
– micro-services
– ESB pour le découplage (dump pipes)
– containerization: pour la légèreté et la vitesse de déploiement (e.g., Docker)
– automatisation de la chaine de développement et continuous delivery
Merci pour l’article très intéressant.
Une citation la forme: « Encore du travail … » 🙂
Sebastien Dubois il y a d’autres approches que l’approche SOA/ESB/EAI avec tous les services qui s’appellent entre eux dans une sorte de toile d’araignée géante et ou on comprends plus rien.
Pour ceux qui veulent se lancer dans les microservices sans se retrouver dans un bourbier de complexité et de dépendances, je vous conseille de regarder ce que propose DDD/CQRS/EventSourcing.
Quelques articles très interessants et abordables sur le sujet sont ceux de l’equipe derrière Kafka (LinkedIn/Confluent)
http://blog.confluent.io/2015/01/29/making-sense-of-stream-processing/
http://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying
D’autres articles interessants mais qui demandent de connaitre un peu mieux le vocabulaire DDD / CQRS:
http://docs.geteventstore.com/introduction/event-sourcing-basics/
http://www.udidahan.com/2009/12/09/clarified-cqrs/
Les performances sont très bonnes avec ce type d’architecture car le modele de READ est adapté aux besoins d’affichage / UX, et le modele de write est un log append-only (mecanical sympathy).
Chaque service organise ses données comme il veut de manière autonome en fonction de l’event log commun. Tous les microservices recoivent les memes events, donc tous les microservices ont acces aux memes données et un microservice n’a pas nécessairement besoin d’appeler les autres microservices. Si le but est d’aggréger des vues de 4 microservices, on peut faire 4 requetes en parallele sur les 4 microservices coté client (avec un spinner pour chaque appel) ou alors faire une requete sur une sorte de proxy dont le role est juste d’aggréger coté serveur (bref juste pour sauver 3 requetes http)
@Sebastien : l’article de Mark Little pose bien le problème SOA/Microservices et les relations entre eux.
En J2EE on faisait des composants : briques logicielles « indépendantes » que l’application agrégeait. Ces briques pouvaient même être distribuées sur plusieurs nœuds dans différents containers 😉 . Cela ressemble fortement à ce qui est décrit ici (mise à part que CORBA replace HTTP/JSON). Et à la fin tout se termine en plat de spaghettis parce qu’on est des huamins.
Bon trolldi à tous, le sujet s’y prête.