Comment développer des microservices
Bonnes pratiques pour la transition vers une architecture de microservices
Sten Pittet
Product Manager
Supposons que votre app repose sur un code unique, qu'elle soit assez volumineuse et monolithique. Elle fonctionnait bien, jusqu'à ce qu'elle ne fonctionne plus. Vous aimeriez qu'elle puisse évoluer pour qu'elle devienne plus résiliente, évolutive et déployable indépendamment. Pour ce faire, vous devez repenser la structure de l'app au niveau granulaire des microservices.
Les microservices gagnent en popularité à mesure que les apps se font de plus en plus distribuées et complexes. Le principe directeur des microservices consiste à développer des apps en divisant les composants métier en services susceptibles d'être déployés et exploités indépendamment les uns des autres. La séparation des préoccupations entre les services est définie comme des « limites de service ».
Les limites des services sont étroitement liées aux exigences métier et aux limites de hiérarchie organisationnelle. Les services individuels peuvent être liés à des équipes, des budgets et des feuilles de route distincts. Certains exemples de limites de service peuvent être les services de « traitement des paiements » et d'« authentification de l'utilisateur ». Les microservices diffèrent des pratiques de développement de logiciels héritées dans lesquelles tous les composants ont été regroupés.
Ce document fera référence à une start-up imaginaire appelée « Pizzup » afin d'illustrer l'application des microservices à un éditeur de logiciels moderne.
Essayez Compass gratuitement
Améliorez votre expérience de développement, cataloguez tous les services et améliorez l'intégrité des logiciels.
Comment développer des microservices
Étape 1 : commencez par un monolithe
La première bonne pratique des microservices est que vous n'en avez probablement pas besoin. Si vous n'avez pas d'utilisateurs pour votre app, il y a de fortes chances que les exigences de l'entreprise changent rapidement lors du développement de votre produit minimum viable (MVP). Cela est simplement dû à la nature du développement de logiciels et au cycle de feedback qui doit avoir lieu pendant que vous identifiez les capacités métier clés que votre système doit fournir. Les microservices ajoutent un surcoût exponentiel et plus de complexité de gestion. C'est pourquoi il est beaucoup moins coûteux pour les nouveaux projets de conserver l'ensemble du code et de la logique dans une base de code unique, car il est plus facile de déplacer les limites des différents modules de votre app.
Par exemple, avec Pizzup, nous commençons par un problème simple à résoudre : nous voulons que les clients puissent commander des pizzas en ligne.
Ressource connexe
Microservices et architecture monolithique
DÉCOUVRIR LA SOLUTION
Améliorez votre expérience de développement grâce à Compass
En réfléchissant à la question de la commande de pizzas, nous identifions les différentes capacités requises dans notre app afin de répondre à ce besoin. Nous devrons gérer une liste des différentes pizzas que nous pouvons préparer, permettre aux clients de choisir de commander une ou plusieurs pizzas, gérer le paiement, planifier la livraison, etc. On pourrait laisser nos clients créer un compte dans le but de faciliter leur nouvelle commande la prochaine fois qu'ils utiliseront Pizzup. Et après avoir échangé avec les premiers utilisateurs, on pourrait s'apercevoir que le suivi en direct de la livraison et l'assistance mobile nous donneront un avantage sur la concurrence.
Ce qui était un simple besoin au départ se transforme rapidement en une liste de nouvelles fonctionnalités.
Les microservices fonctionnent bien lorsque vous avez une solide compréhension des différents services requis par votre système. Toutefois, les microservices sont beaucoup plus difficiles à gérer si les exigences fondamentales d'une app ne sont pas bien définies. Il est en effet assez coûteux de redéfinir les interactions de service, les API et les structures de données dans les microservices, car il y a généralement beaucoup plus de pièces mobiles qui nécessitent d'être coordonnées. Nous vous conseillons d'aller au plus simple jusqu'à ce que vous ayez reçu suffisamment de feedback d'utilisateurs pour être sûr que les besoins fondamentaux de vos clients sont compris et planifiés.
Il convient toutefois de faire preuve de prudence, car le développement d'un monolithe peut rapidement conduire à un code compliqué qu'il est difficile de décomposer en plus petits composants. Il est préférable d'identifier clairement les modules afin de pouvoir les extraire ultérieurement du monolithe. Vous pouvez également commencer par séparer la logique de l'interface web et faire en sorte qu'elle interagisse avec votre back-end via une API RESTful sur HTTP. Cela facilite la transition vers les microservices, lorsque vous déplacez certaines ressources API vers différents services.
Étape 2 : Organisez vos équipes de manière appropriée
Jusqu'à présent, il pouvait sembler que la mise en place de microservices était essentiellement une affaire technique. Il faut diviser une base de code en plusieurs services, implémenter les bons modèles afin de limiter la casse et de récupérer après des problèmes de réseau, gérer la cohérence des données, surveiller la charge du service, etc. Vous devrez appréhender de nombreux nouveaux concepts, mais la chose la plus importante à ne pas ignorer, c'est que vous devrez restructurer la façon dont vos équipes sont organisées.
La loi de Conway est bien réelle et peut être observée dans tous les types d'équipes. Si une équipe de développement logiciel est organisée avec une équipe de back-end, une équipe front-end et une équipe opérationnelle travaillant indépendamment, elle livrera aveuglément des monolithes front-end et back-end distincts à l'équipe opérationnelle pour les mettre en production. Ce type de structure n'est pas approprié pour les microservices, car chaque service doit être considéré comme son propre produit qui doit être livré indépendamment des autres.
Au lieu de cela, vous devriez créer des équipes DevOps plus petites qui possèdent toutes les compétences nécessaires pour développer et maintenir les services dont elles sont responsables. Cette organisation des équipes présente des avantages importants. Tout d'abord, vos développeurs ont une meilleure compréhension de l'impact de leur code en production. Cela les aide à produire de meilleures versions et réduit le risque de voir des problèmes livrés aux clients. Ensuite, les déploiements deviennent une seconde nature pour chaque équipe, car elles travaillent ensemble sur des améliorations du code ainsi que l'automatisation du pipeline de déploiement.
Étape 3 : fractionnez le monolithe pour développer une architecture de microservices
Lorsque vous avez identifié les limites de vos services et compris comment restructurer vos équipes, vous pouvez commencer à fractionner votre monolithe afin de créer des microservices. Voici les points clés à prendre en compte à ce moment-là.
Veillez à ce que communication entre les services reste simple grâce aux API REST
Si vous n'utilisez pas déjà une API RESTful, c'est le moment idéal pour l'adopter. Comme l'explique Martin Fowler, vous souhaitez avoir « des points d'ancrage intelligents et des pipes stupides ». Cela signifie que le protocole de communication entre vos services doit être aussi simple que possible, et uniquement transmettre les données, sans les altérer. La magie opère dans les points d'ancrage eux-mêmes : ils reçoivent une demande, la traitent et émettent une réponse en retour.
Les architectures de microservice s'efforcent de maintenir la simplicité afin d'éviter un couplage étroit des composants. Dans certains cas, vous pouvez utiliser une architecture orientée événement grâce à des communications asynchrones basées sur des messages. Mais encore une fois, vous devriez vous pencher sur des services de file d'attente de messages de base tels que RabbitMQ et éviter d'ajouter de la complexité aux messages transmis sur le réseau.
Divisez les données en contextes ou domaines de données définis
Les apps monolithiques utilisent une base de données unique pour toutes leurs fonctionnalités métier. À mesure qu'un monolithe est fractionné en microservices, cette base de données unique peut ne plus être judicieuse. Une base de données centrale peut devenir un goulot d'étranglement pour l'évolution du trafic. Si un service particulier accède à la base de données avec une charge élevée, il peut interrompre l'accès à la base de données d'autres services. En outre, une base de données unique peut se transformer en goulot d'étranglement de collaboration pour plusieurs équipes qui tentent de modifier simultanément le schéma. Cela peut nécessiter la fragmentation de la base de données ou l'ajout d'outils de stockage de données supplémentaires pour répondre aux besoins de données des microservices.
Le refactoring (ou remaniement) d'un schéma de base de données monolithique peut s'avérer délicat. Il est important d'identifier clairement les ensembles de données dont chaque service a besoin et les chevauchements éventuels. Cette planification de schéma peut être effectuée à l'aide de contextes définis, qui sont un modèle de design orienté domaine. Un contexte défini délimite un système autonome, notamment ce qui peut entrer et sortir de ce système.
Dans ce système, lorsqu'un utilisateur accède à une commande, vous pouvez afficher les informations client dans le tableau, qui peut également être utilisé pour remplir la facture gérée par le système de facturation. Cela peut sembler logique et simple, mais avec les microservices, les services doivent être découplés afin que les factures soient accessibles même si le système de commande est en panne. En outre, ils vous permettent d'optimiser ou de faire évoluer le tableau des factures indépendamment des autres. Chaque service peut finir par avoir sa propre base de données pour accéder aux données dont il a besoin.
Cela introduit de nouveaux problèmes, car des données seront inévitablement dupliquées dans différentes bases de données. Les contextes définis peuvent identifier la meilleure stratégie pour gérer les données partagées ou dupliquées. Vous pouvez adopter une architecture orientée événements afin de faciliter la synchronisation des données entre plusieurs services. Par exemple, vos services de suivi de facturation et de livraison peuvent être à l'écoute des événements émis par le service de compte lorsque des clients mettent à jour leurs informations personnelles. À la réception de l'événement, ces services mettront à jour leur base de données en conséquence. Cette architecture orientée événement permet de maintenir la simplicité du service de compte, car elle n'a pas besoin de connaître les autres services dépendants. Elle indique simplement au système ce qu'elle a fait et les autres services écoutent et agissent en conséquence.
Vous pouvez également choisir de conserver toutes les informations relatives aux clients dans le service de compte et de ne conserver qu'une référence de clé étrangère dans votre service de facturation et de livraison. Ces services interagissent alors avec le service de compte pour obtenir les données pertinentes sur le client, au lieu de dupliquer les enregistrements existants. Puisqu'il n'y a pas de solution universelle pour ces problèmes, vous devrez examiner chaque cas spécifique pour déterminer la meilleure approche.
Développez votre architecture de microservices pour les pannes
Nous avons vu les grands avantages des microservices par rapport à une architecture monolithique. Ils sont plus petits et spécialisés, ce qui les rend faciles à comprendre. Ils sont dissociés, ce qui signifie que vous pouvez remanier un service sans crainte d'endommager les autres composants du système ou de ralentir le développement des autres équipes. Ils offrent également plus de flexibilité à vos développeurs qui peuvent choisir différentes technologies si nécessaire sans être contraints par les besoins d'autres services.
En bref, disposer d'une architecture de microservices facilite le développement et la maintenance de chaque capacité métier. Mais les choses se compliquent lorsque vous regardez l'ensemble des services et la manière dont ils doivent interagir pour exécuter des actions. Votre système est maintenant distribué avec plusieurs points de défaillance, et vous devez y faire face. Vous devez prendre en compte non seulement les cas où un service ne répond pas, mais également être en mesure de gérer des réponses réseau plus lentes. La reprise d'activité suite à une panne peut également s'avérer difficile à certains moments, car vous devez vous assurer que les services qui sont remis en route ne sont pas saturés par les messages en attente.
Quand vous commencez à extraire des capacités de vos systèmes monolithiques, assurez-vous que vos designs sont conçus dès le début en pensant aux possibles défaillances.
Mettez l'accent sur la surveillance pour faciliter les tests de microservices
Les tests constituent un autre inconvénient des microservices par rapport à un système monolithique. Une application développée en tant que base de code unique n'a pas besoin de grand-chose pour que son environnement de test soit opérationnel. Dans la plupart des cas, vous devrez démarrer un serveur back-end couplé à une base de données pour pouvoir exécuter votre suite de tests.
Dans l'univers des microservices, tout n'est pas aussi simple. Les tests unitaires seront encore assez similaires à ceux du monolithe et cela ne devrait pas vous sembler compliqué. Cependant, lorsqu'il est question d'intégration et de tests système, les choses se compliquent. Vous devrez peut-être démarrer plusieurs services à la fois, disposer de différentes bases de données opérationnelles, et votre configuration peut nécessiter des files d'attente de messages dont vous n'aviez pas besoin avec votre monolithe. Dans cette situation, effectuer des tests fonctionnels devient beaucoup plus coûteux, et le nombre croissant de pièces mobiles rend très difficile la prédiction des différents types de défaillances potentielles.
La surveillance permet d'identifier les problèmes rapidement et de répondre en conséquence. Vous devrez comprendre les bases de référence de vos différents services et réagir non seulement lorsque ces services tombent en panne, mais aussi lorsqu'ils se comportent de façon inattendue. L'un des avantages de l'adoption d'une architecture de microservices est que votre système doit être résilient à une défaillance partielle. Par conséquent, si vous commencez à observer des anomalies dans le service de suivi de livraison de notre app Pizzup, ce ne sera pas aussi grave que s'il s'agissait d'un système monolithique. Notre app doit être conçue de manière à ce que tous les autres services répondent correctement et permettent à nos clients de commander des pizzas pendant que nous restaurons le suivi en direct.
Adoptez la livraison continue pour réduire les frictions de déploiement
Livrer manuellement un système monolithique en production est un effort fastidieux et risqué, mais réalisable. Bien sûr, nous ne recommandons pas cette approche et encourageons chaque équipe de développement à adopter la livraison continue pour tous les types de développement, mais au début d'un projet, vous pouvez effectuer vos premiers déploiements vous-même via la ligne de commande.
Cette approche n'est pas durable lorsque vous disposez d'un nombre croissant de services qui doivent être déployés plusieurs fois par jour. Par conséquent, dans le cadre de votre transition vers les microservices, l'adoption de la livraison continue est essentielle afin de réduire les risques d'échec de livraison, et de vous assurer que votre équipe se concentre sur le développement et l'exécution de l'app, plutôt que d'être bloquée sur son déploiement. Pratiquer la livraison continue signifie également que votre service a réussi les tests d'acceptation avant d'être déployé en production. Bien sûr, des bugs surviendront, mais au fil du temps, vous développerez une suite de tests robuste qui devrait augmenter la confiance de votre équipe dans la qualité des livraisons.
L'exécution de microservices n'est pas un sprint
Les microservices constituent une bonne pratique populaire, largement adoptée dans le secteur. Pour les projets complexes, ils offrent une plus grande flexibilité dans le développement et le déploiement des logiciels. Ils aident également à identifier et à formaliser les composants métier de votre système, ce qui est pratique lorsque plusieurs équipes travaillent sur la même app. Mais il y a également des inconvénients évidents à la gestion des systèmes distribués, et la division d'une architecture monolithique ne devrait être réalisée qu'en s'appuyant sur une solide compréhension des limites du service.
Le développement de microservices doit être considéré comme un parcours plutôt que comme un objectif immédiat pour une équipe. Commencez modestement pour comprendre les exigences techniques d'un système distribué, comment échouer de façon normale et faire évoluer des composants individuels. Ensuite, vous pouvez progressivement extraire plus de services à mesure que vous gagnez de l'expérience et des connaissances.
La migration vers une architecture des microservices n'a pas besoin d'être effectuée en un seul effort holistique. Une stratégie itérative de migration séquentielle de petits composants vers des microservices est plus sûre. Identifiez les limites des services les mieux définis au sein d'une app monolithique établie et travaillez de manière itérative pour les dissocier dans leur propre microservice.
Conclusion…
Pour récapituler, les microservices sont une stratégie qui est bénéfique à la fois pour le processus de développement de code technique brut et pour la stratégie globale d'organisation de l'entreprise. Ils aident à organiser les équipes en unités qui se concentrent sur le développement et la possession de fonctions métier spécifiques. Cette priorité granulaire améliore la communication et l'efficacité globales de l'entreprise. Des compromis sont nécessaires pour profiter des avantages des microservices. Les limites de service doivent être clairement définies avant de migrer vers une architecture de microservices.
Bien qu'une architecture de microservices présente de nombreux avantages, elle augmente également la complexité. Atlassian a développé Compass pour aider les entreprises à gérer la complexité des architectures distribuées à mesure qu'elles évoluent. Il s'agit d'une plateforme de partage d'expériences extensible qui rassemble des informations déconnectées sur tous les résultats d'ingénierie et la collaboration des équipes dans un emplacement central et interrogeable.
Partager cet article
Thème suivant
Lectures recommandées
Ajoutez ces ressources à vos favoris pour en savoir plus sur les types d'équipes DevOps, ou pour les mises à jour continues de DevOps chez Atlassian.