Une architecture de microservices se compose d’un ensemble de petits services autonomes. Chaque service est autonome et doit implémenter une fonctionnalité unique dans un contexte borné. Un contexte borné est une division naturelle au sein d’une entreprise qui fournit une délimitation explicite dans laquelle un modèle de domaine existe.
Que sont les microservices ?
Les microservices sont de petite taille, indépendants et faiblement couplés. Une équipe réduite de développeurs peut écrire un service et en assurer la maintenance.
Chaque service est un code base distinct, qui peut être géré par une petite équipe de développement.
Les services peuvent être déployés de manière indépendante. Une équipe peut mettre à jour un service existant sans avoir à recréer et redéployer l’application entière.
Les services sont responsables de la persistance de leurs propres données ou de leur propre état externe. Ils se distinguent en cela du modèle traditionnel dans lequel une couche de données distincte gère la persistance des données.
Les services communiquent entre eux à l’aide d’API bien définies. Les détails de l’implémentation interne de chaque service sont cachés aux autres services.
Prend en charge la programmation polyglotte. Par exemple, les services n’ont pas besoin de partager une pile de technologies, des bibliothèques ou des frameworks identiques.
Outre les services proprement dits, une architecture de microservices type est constituée d’autres composants :
Gestion/orchestration. Ce composant est chargé de placer les services sur des nœuds, d’identifier les défaillances, de rééquilibrer les services entre les nœuds, etc. En général, ce composant est une technologie prête à l’emploi comme Kubernetes, plutôt qu’un élément personnalisé.
Passerelle d’API : la passerelle d’API est le point d’entrée des clients. Au lieu d’appeler directement les services, les clients appellent la passerelle d’API, qui transfère l’appel aux services appropriés sur le back-end.
L’utilisation de la passerelle d’API offre les avantages suivants :
Il dissocie les clients des services. Les services peuvent être versionnés ou refactorisés sans avoir à mettre à jour tous les clients.
Les services peuvent utiliser des protocoles de messagerie qui ne sont pas compatibles avec le web, comme AMQP.
La passerelle d’API peut exécuter d’autres fonctions transversales, telles que l’authentification, la journalisation, la terminaison SSL et l’équilibrage de charge.
Stratégies prêtes à l’emploi, telles que la limitation, la mise en cache, la transformation ou la validation.
Avantages
Agilité. Les microservices sont déployés de manière indépendante, ce qui facilite la gestion des correctifs de bogues et des nouvelles fonctionnalités. Vous pouvez mettre à jour un service sans avoir à redéployer l’application entière et effectuer une restauration si une mise à jour est source de problèmes. Dans de nombreuses applications traditionnelles, s’il existe un bogue dans une partie de l’application, il peut bloquer tout le processus de mise en production. Les nouvelles fonctionnalités peuvent être retardées le temps qu’une résolution de bogue soit intégrée, testée et publiée.
Équipes spécialisées de taille restreinte. Un microservice doit être suffisamment petit pour qu’une seule équipe de fonctionnalité puisse le générer, le tester et le déployer. Les petites équipes favorisent une plus grande souplesse. Les grandes équipes ont tendance à être moins productives, car la communication est plus lente, le temps de gestion augmente et l’agilité diminue.
Base de code de petite taille. Dans une application monolithique, les dépendances de code ont tendance à s’entremêler au fil du temps. L’ajout d’une nouvelle fonctionnalité demande de modifier le code à de nombreux endroits. En ne partageant ni code, ni magasins de données, une architecture de microservices minimise les dépendances, ce qui facilite l’ajout de nouvelles fonctionnalités.
Pot-pourri de technologies. Les équipes peuvent choisir la technologie qui convient le mieux à leur service à l’aide de diverses piles technologiques.
Isolation des erreurs : Si un microservice individuel devient indisponible, cela ne perturbera pas l'ensemble de l'application, pour autant que les microservices en amont soient conçus pour gérer correctement les défaillances. Par exemple, vous pouvez implémenter le modèle disjoncteur ou concevoir votre solution afin que les microservices communiquent entre eux à l’aide de modèles de messagerie asynchrones.
Extensibilité. Les services peuvent être mis à l’échelle de manière indépendante, ce qui permet d’effectuer un scale-out de sous-systèmes qui nécessitent plus de ressources, sans effectuer un scale-out de l’ensemble de l’application. En utilisant un orchestrateur tel que Kubernetes, vous pouvez emballer une plus grande densité de services sur un seul hôte, ce qui permet une utilisation plus efficace des ressources.
Isolation des données. Il est beaucoup plus facile d’effectuer des mises à jour de schéma, car un seul microservice est concerné. Dans une application monolithique, les mises à jour de schéma peuvent devenir très difficiles, car les différentes parties de l’application impliquer les mêmes données, d’où le risque de modifier le schéma.
Défis
Les avantages des microservices ont néanmoins un prix. Voici certains des défis à prendre en compte avant de se lancer dans une architecture de microservices.
Complexité : une application de microservices possède plus d’éléments mobiles qu’une application monolithique équivalente. Si chaque service est plus simple, le système dans son ensemble est plus complexe.
Développement et test. L’écriture d’un petit service qui s’appuie sur d’autres services dépendants nécessite une approche différente de celle consistant à écrire une application monolithique ou en couches traditionnelle. Les outils existants ne sont pas toujours conçus pour fonctionner avec des dépendances de services. Refactoriser au-delà des limites des services peut s’avérer difficile. Il est aussi difficile de tester les dépendances de services, en particulier quand l’application évolue rapidement.
Manque de gouvernance : l’approche décentralisée de création de microservices présente des avantages, mais elle peut aussi être une source de problèmes. Vous pouvez en effet vous trouver face à une diversité de langages et de frameworks telle que l’application devient difficile à gérer. Il peut être utile de mettre en place certains standards à l’échelle du projet, sans trop limiter la flexibilité des équipes. Cela vaut en particulier pour les fonctionnalités transversales, telles que la journalisation.
Surcharge du réseau et latence : l’utilisation de nombreux services granulaires de petite taille peut se traduire par une intensification des communications entre les services. De même, si la chaîne des dépendances de services devient trop longue (le service A appelle le service B, qui appelle le service C, etc.), la latence supplémentaire qui s’ensuit peut devenir un problème. Vous devrez faire preuve de circonspection au moment de concevoir des API. Évitez les API trop bavardes, envisagez des formats de sérialisation et cherchez à utiliser des modèles de communication asynchrone comme le nivellement de charge basé sur les files d’attente.
Intégrité des données : Chaque microservice étant responsable de la persistance de ses propres données. Par conséquent, la cohérence des données entre plusieurs services peut constituer un défi. Différents services conservent les données à différents moments, en utilisant différentes technologies et avec des niveaux de réussite potentiellement différents. Lorsque plusieurs microservices sont impliqués dans la persistance de données nouvelles ou modifiées, il est peu probable que la modification complète des données puisse être considérée comme une transaction ACID. La technique est plutôt alignée sur BASE (Basically Available, Soft state, and Eventually consistent). Adoptez la cohérence éventuelle dans la mesure du possible.
Gestion : une expérience réussie avec les microservices exige une culture DevOps mature. La mise en place d’une journalisation corrélée entre les services peut poser des problèmes. En règle générale, la journalisation doit mettre en corrélation plusieurs appels de services pour une même opération utilisateur.
Gestion des versions : les mises à jour apportées à un service ne doivent pas perturber les services qui en dépendent. Plusieurs services pouvant être mis à jour à tout moment, sans une conception minutieuse, vous risquez de rencontrer des problèmes de compatibilité descendante ou ascendante.
Ensemble de compétences : les microservices sont des systèmes hautement distribués. Évaluez avec soin les chances de réussite en tenant compte des compétences et de l’expérience de l’équipe.
Meilleures pratiques
Modélisez les services autour du domaine de l’entreprise.
Décentralisez tout. Les équipes individuelles sont chargées de concevoir et de créer des services. Évitez de partager du code ou des schémas de données.
Le stockage de données doit être privé par rapport au service qui détient les données. Utilisez le stockage le mieux adapté à chaque service et type de données.
Les services communiquent via des API bien conçues. Évitez de divulguer les détails d’une implémentation. Les API doivent modéliser le domaine, et non l’implémentation interne du service.
Évitez le couplage entre les services. Le couplage trouve souvent son origine dans les schémas de base de données partagés et les protocoles de communication rigides.
Déchargez les problèmes transversaux, tels que l’authentification et la terminaison SSL, sur la passerelle.
Maintenez la connaissance du domaine à l’extérieur de la passerelle. La passerelle doit traiter et acheminer les demandes des clients sans connaître les règles d’entreprise ou la logique du domaine. Sinon, la passerelle devient une dépendance et peut provoquer un couplage entre les services.
Le couplage entre les services doit être faible et leur cohésion fonctionnelle élevée. Les fonctions susceptibles de changer en même temps doivent être empaquetées et déployées ensemble. Si elles résident dans des services distincts, ces services finissent par être fortement couplés, car une modification dans un service nécessite la mise à jour de l’autre service. Une communication proéminente entre deux services peut être le signe d’un couplage étroit et d’une faible cohésion.
Isolez les défaillances. Utilisez des stratégies de résilience pour empêcher que les défaillances au sein d’un service se répercutent en cascade. Consultez Modèles de résilience et Conception d'applications fiables.
Étapes suivantes
Pour obtenir des instructions détaillées sur la création d’une architecture de microservices sur Azure, consultez Conception, génération et exploitation de microservices sur Azure.