Test des applications orientées microservices

Bonjour, Habr!



Poursuivant l'étude de la thématique des microservices , nous avons décidé de vous proposer la traduction d'un article sur le test des MOA (microservices-applications orientées). Récemment, nous avons déjà abordé le sujet des tests , mais dans le cas des microservices, les tests unitaires réguliers ne suffisent pas, vous devez également prendre en compte les aspects liés à CI / CD et à d'autres choses qui seront abordées dans cet article.







Les microservices sont un nouveau style d'architecture logicielle utilisé dans la création de systèmes distribués et sont de plus en plus mis en œuvre dans les entreprises opérant sur le Web, y compris les plus grandes d'entre elles. Par exemple, Netflix et Amazon ont adopté une architecture de microservices pour accélérer considérablement la sortie de produits logiciels. Dans le même temps, les systèmes monolithiques plus anciens ne peuvent pas évoluer à une vitesse qui répondrait aux défis modernes.



Mais les avantages qu'une architecture de microservice peut apporter sont aussi bons que les meilleures pratiques pour la prendre en charge peuvent être testées. Lors de la conception de tests pour valider des systèmes de microservices, où le taux de libération peut être décrit comme un éclair, une réflexion innovante est nécessaire, tant au niveau micro que macro.



Ensuite, nous explorerons les trois types d'applications orientées microservices, discuterons de certains des défis que vous devrez relever pour les tester et parlerons de la façon dont les tests sont écrits pour apprécier pleinement les avantages des microservices.



En bref sur les microservices



Avant d'entrer dans certaines des subtilités de la conception de tests pour les microservices, examinons ce que sont les microservices. Microservice est un composant logiciel détaillé qui a reçu une définition sémantique claire; cependant, le microservice porte son propre ensemble de données et ne dépend pas d'autres structures de données et sources de données. Chaque microservice a son propre cycle de déploiement, donc une fois que des modifications ont été apportées au microservice, vous pouvez le libérer sans interrompre le travail des autres microservices dans le cadre de l'application avec laquelle ce microservice s'exécute.



Avantages des microservices par rapport aux applications monolithiques



Jetons également un coup d'œil à ce qu'un microservice n'est pas. La figure suivante montre un exemple d'application monolithique typique.







Chiffre: 1: Les architectures d'application monolithiques ont généralement une forte cohésion des composants



Les composants Clients, Produits, Commandes et (Commentaires) peuvent être considérés comme un ensemble de classes écrites dans un langage orienté objet tel que Java ou C #, où clients est un tableau d'objets correspondant à des clients, des produits - un tableau d'objets correspondant à des produits, etc. L'objet client peut utiliser à la fois l'objet client et l'objet produit. Ou, du fait que tous les composants d'une application monolithique accèdent à la même base de données, l'objet de commande peut accéder directement à la base de données et obtenir toutes les informations sur le produit et la commande nécessaires pour effectuer les tâches. L'accès direct à la base de données n'est pas seulement possible - et à quel point il contredit l'esprit de la programmation orientée objet basée sur un mappage objet-relationnel ORM - mais il est également utilisé activement, en particulier dans les domaines où il existe une forte demande de fonctionnalités prêtes à l'emploi à la date convenue, quel que soit le coût.



Le résultat est un système étroitement couplé, parfois fragile, où la sortie d'une nouvelle version d'une application nécessite une coordination importante entre toutes les équipes de développement impliquées dans le développement de ce système. En raison du couplage fort, l'ensemble du cycle de libération ne peut pas aller plus vite que le travail le plus lent de renégociation d'une dépendance. En d'autres termes, s'il est temps de mettre à jour l'application et d'y ajouter une nouvelle fonctionnalité par les clients et une nouvelle fonctionnalité par les produits, la publication n'aura pas lieu tant que ces deux fonctionnalités ne seront pas prêtes. S'il faut un jour pour mettre à jour un produit et trois semaines pour faire un changement de client, la publication aura lieu au plus tôt trois semaines. De plus, ce qui aggrave encore la situation, lors de la mainlevée, il peut être nécessaire non seulement de coordonner le nouveau code concernant les clients et les marchandises,mais aussi apporter des modifications au schéma de la base de données, et cela devra également être géré pendant le processus de publication.



La publication de modifications dans une base de données est une entreprise très délicate. Il existe toujours un risque d'effets secondaires involontaires lors de la modification de la structure de la base de données. N'oubliez pas que si un composant peut accéder à la base de données, il y accédera et même effectuera des opérations sur les données qui n'entrent pas dans le cadre de ce composant. Une telle «manipulation hors zone» peut conduire à des pannes d'autres composants, et ces pannes peuvent passer inaperçues jusqu'à ce qu'une catastrophe se produise. Parfois, un danger potentiel peut être trouvé dans le code jusqu'à la mise en production de ce code. Malheureusement, cela arrive tout le temps.

Certaines entreprises sont prêtes à supporter les cycles de publication lents qui sont typiques pour travailler avec des applications monolithiques. Mais, si nous parlons d'une entreprise qui prend en charge des centaines de milliers d'utilisateurs, et doit en même temps maintenir des milliers de composants en état de fonctionnement, alors le rythme "pas plus rapide que la sortie du composant le plus tardif" est inacceptable .



Applications orientées microservices



Dans une application orientée microservices (MOA), chaque composant fonctionnel est décomposé en unités les plus petites possibles avec une fonctionnalité prononcée (dans des limites raisonnables). Dans ce cas, chacun de ces composants fonctionnels est organisé comme un microservice. Chaque entreprise a son propre bagage de code hérité, ainsi qu'une culture d'entreprise qui doit être respectée, il est donc impossible d'écrire "comme des notes" comment exactement la décomposition doit être effectuée.



Lorsqu'il s'agit de décomposer une application monolithique dans MOA, la clé à retenir est que le meilleur est l'ennemi du bien. Assurez-vous que chaque microservice est structuré selon sa définition sémantique, que le microservice a ses propres données et son propre cycle de publication. La profondeur de la mise en œuvre dépend de ce que l'entreprise peut se permettre, en fonction du temps disponible, de l'expérience des employés et des ressources disponibles. Certains microservices peuvent avoir une seule fonction, d'autres peuvent avoir plusieurs fonctions.

Il existe trois types de MOA : synchrone , asynchrone et hybride .



Applications orientées microservices synchrones



La figure 2 montre un MOA synchrone. La communication interservice est un principe de requête-réponse typique des interactions HTTP sur le Web.







Figure 2: Application orientée microservice basée sur une communication interservice synchrone



Chaque microservice est segmenté derrière le serveur HTTP, ce qui permet d'accéder à la logique de ce microservice. Un microservice spécifique ne connaît que son propre domaine de responsabilité; il peut également connaître l'interface pour interagir avec un autre microservice, mais il ne peut pas voir la logique interne d'un autre service. De plus, le microservice ne connaît que ses propres données. Les magasins de données d'autres microservices ne lui sont pas connus et ne lui sont pas accessibles. Il est impossible de «détourner» les données d'un autre microservice en accédant directement à l'entrepôt de données correspondant. La seule façon d'obtenir des données du microservice et d'y transférer de nouvelles données est d'interagir avec lui via l'interface publique.



L'un des avantages des MOA synchrones est leur indépendance. Par exemple, le microservice Clients présenté ci-dessus peut être mis à jour à tout moment qui lui convient. Il n'y a pas de dépendances externes qui doivent être ajustées à cela. Tant que le microservice ne change pas son interface publique, ainsi que la structure des données qu'il a l'intention de consommer à partir de la requête et de renvoyer en tant que réponse, le risque de briser toute l'architecture MOA est minime.



De par sa nature même, l'architecture MOA est telle qu'elle conserve sa propre intégrité structurelle. Étant donné que le microservice lui-même transporte ses propres données, son travail n'affecte pas les magasins de données d'autres services. Puisqu'un microservice est représenté comme un ensemble d'URL HTTP et de structures de données associées, construit sur un principe de demande-réponse, les limites de l'interface du microservice sont clairement définies.



Les MOA synchrones sont de plus en plus populaires. De nombreuses interfaces MOA synchrones sont basées sur le paradigme REST, un style qui existe depuis 2000de l'année. Mais, malgré toute sa popularité, MOA a un inconvénient: la faible vitesse. Les consommateurs d'un microservice synchrone ne s'exécuteront jamais plus vite que ce microservice ne peut gérer les demandes et les réponses. Cela peut être un goulot d'étranglement majeur, en particulier lorsqu'il s'agit de microservices, dont les processus prennent beaucoup de temps à s'exécuter. Un exemple est un service analytique complexe qui consomme et traite des téraoctets de données. Peu de clients accepteront de s'asseoir et d'attendre quelques minutes consécutives que le service s'arrête. Il serait plus pratique d'indiquer au microservice le travail à effectuer, puis d'être averti lorsque les résultats sont prêts.



Dans des situations comme celle-ci, il est plus pratique d'adopter une approche asynchrone pour la conception de microservices.



Applications asynchrones orientées microservices



La figure 3 ci-dessous montre une mise en œuvre MOA asynchrone, où la communication de service à service est fournie par l'échange de messages entre les parties concernées. En général, cette interaction est appelée «feu et oublie».







Figure 3: L'architecture MOA asynchrone est basée sur la messagerie



Dans l'architecture MOA asynchrone, les messages peuvent être générés de manière aléatoire, ou en réponse à un événement donné. Par exemple, lorsque (comme indiqué dans l'image ci-dessus) une commande est créée dans le microservice Commandes, ce service peut publier un événement orders_created



et le placer dans une file d'attente de messages associée ., qui écoute un autre microservice, la facturation (non représentée sur la figure) et l'acceptation des messages entrants. Le microservice de facturation récupère le message d'information sur la commande et le traite de manière pertinente du point de vue de la facturation.



L'avantage d'une approche asynchrone de la conception d'applications orientées microservices est qu'il n'y a pas de goulots d'étranglement dans un tel système et, par conséquent, il est extrêmement efficace. L'inconvénient est qu'un tel système est très difficile à créer puis à gérer.

Pour les systèmes asynchrones à grande échelle comme Uber, il est normal de traiter des milliers de messages par seconde. Le débogage d'un tel système est difficile car ses workflows n'ont pas de trajectoires claires. Il ne s'agit pas de faire d'abord une action puis d'en faire une autre; la logique est déclenchée en fonction du message reçu, c'est-à-dire que tout peut arriver à tout moment.



Cela doit être gardé à l'esprit lors de l'élaboration de stratégies de test. Par exemple, un système asynchrone est peu pratique, dont les performances dépendent des temps de requête et de réponse, car il n'y aura jamais de correspondance biunivoque "une requête-une réponse".



Applications hybrides orientées microservices



L'approche équilibrée de la mise en œuvre d'une application orientée microservices est hybride. Les services sont simultanément synchrones, c'est-à-dire que la communication directe demande-réponse est prise en charge entre eux et en même temps asynchrone; c'est-à-dire que certains des messages sont générés conjointement avec ou à la suite d'une messagerie synchrone.



La figure 4 illustre les modèles de communication utilisés dans une approche hybride des applications orientées microservices. Le microservice Clients est représenté à la fois comme une URL associée à un serveur HTTP et comme une file d'attente dans un courtier de messages.







Figure 4: Une approche hybride de la conception d'applications orientées microservices qui utilise à la fois des options de communication synchrones et asynchrones entre les services et les consommateurs.

Vous pouvez ajouter un client au microservice à l'aide de la communication requête-réponse HTTP standard. La demande est reçue et traitée, puis une réponse est générée. Cependant, avant qu'une réponse ne soit générée, un message contenant des informations sur le nouveau client est publié dans la file d'attente de messages compagnon afin que d'autres services intéressés puissent le consommer. Les informations envoyées à la file d'attente de messages peuvent être les mêmes que celles générées dans la réponse HTTP, ou légèrement différentes, à la discrétion du microservice. Tout dépend de la façon dont le microservice est conçu et des accords QoS que le microservice doit appliquer.



GraphQLEst une technologie API qui prend en charge la communication synchrone et asynchrone entre un consommateur et un service. En savoir plus sur cette technique et les abonnements GraphQL ici .



La caractéristique la plus importante de l'approche hybride est qu'elle combine les mérites des deux autres approches. Mais il y a des inconvénients qui l'accompagnent, en particulier des goulots d'étranglement potentiels qui réduisent les performances, et la complexité supplémentaire associée à la nécessité de prendre en charge deux types fondamentalement différents d'interfaces utilisées par le microservice «in» et «out».



Des difficultés surviennent lors de la conception de tests pour les microservices



Lorsqu'il s'agit de tester de telles applications, la première chose à retenir est qu'il est très rare qu'un seul microservice soit partagé par plusieurs MOA. En règle générale, un microservice est l'un des nombreux dans un domaine spécifique au sein d'une application. L'avantage d'une approche de conception d'architecture d'application orientée microservices est un transfert de code plus rapide vers et depuis la production. Netflix, par exemple, a plus de 4000 déploiements par jour .) Ce taux de publication n'est tout simplement pas possible dans un environnement d'application monolithique traditionnel.



Il convient également de se rappeler que les tests MOA doivent avoir lieu aux niveaux micro et macro.



Test de micro-niveau



Au niveau micro, chaque service doit être minutieusement testé dans sa zone de responsabilité. Selon certaines interprétations, une fonction est considérée comme une limite de microservice.



Allez au-delà des tests unitaires traditionnels



Il est conseillé de porter une attention particulière à la fonction au sein du microservice, étant donné la popularité croissante du paradigme sans serveur , selon lequel le microservice ne doit être présenté que comme une seule fonction. Mais de nombreux testeurs expérimentés ont tendance à se limiter aux tests unitaires lorsqu'ils travaillent avec des microservices. Alors qu'un test unitaire couvre normalement une seule fonction qui fonctionne dans un environnement de test très limité, un microservice est conçu pour servir un public sur le Web. Par conséquent, les conditions de test doivent être extrêmes.



Par exemple, dans le cadre d'un bon test de micro-niveau, vous pouvez exécuter cent mille instances d'un microservice en même temps et voir comment elles se comportent à cette échelle. Il ne suffit pas de tester une seule fonction à la fois en lui appliquant un seul test unitaire. Il est nécessaire d'exécuter de tels tests sur des milliers d'instances de la fonction en même temps, en tenant compte des indicateurs de l'environnement d'hébergement dans lequel vous devrez travailler.



Testez votre unité de déploiement



En plus de tester la fonctionnalité du microservice, vous devez également prendre soin de tester l'unité de déploiement dans laquelle le microservice est publié. En règle générale, les microservices sont déployés en tant que conteneurs dans le cadre d'une technologie d'orchestration telle que Kubernetes ou Docker Swarm . Un aspect important de l'orchestration de conteneurs est d'assurer la résilience à long terme des microservices.



On pense que les microservices peuvent échouer pour diverses raisons, à la fois en raison d'une défaillance de l'hôte et en raison d'erreurs dans le microservice lui-même. Il est tout à fait normal que lors du fonctionnement simultané de milliers de conteneurs, une sorte de dysfonctionnement du courant se produise. L'importance des tests est que la sortie correcte du microservice du jeu n'est pas moins importante que son bon fonctionnement. Des tests de niveau micro garantissent que le microservice prendra vie et s'éteindra proprement, à n'importe quelle échelle du système.



Assurez-vous que tout ce qui vous arrive est enregistré



Les tests doivent également garantir que tous les événements importants se produisant dans le microservice sont correctement consignés - et tout aussi important, ces entrées de journal peuvent être comprises. Dans le monde des microservices, la journalisation est très importante, en particulier pour les MOA asynchrones où il n'y a pas d'exécution séquentielle des comportements. Souvent, seules les données du journal vous aideront à comprendre ce qui se passe dans l'application.



Test de macros



Que le MOA soit synchrone, asynchrone ou hybride, il est montré en mode de test rigoureux. Lorsque vous testez des microservices au niveau macro, vous devez vous assurer que deux aspects sont satisfaisants: la communication interservices et les processus de déploiement.



Assurer une communication interservices intelligente



Les microservices sont par définition indépendants les uns des autres. Ils déterminent ce qu'il faut faire en fonction des informations qu'ils reçoivent, de sorte que la précision de la communication interservices est essentielle au fonctionnement holistique d'une application orientée microservice.



Fournir une communication interservices signifie s'assurer que les bonnes informations arrivent là où elles doivent aller et où elles vont. Les tests doivent pouvoir suivre la manière dont les messages sont échangés et comment ils sont traités. Cela est vrai à la fois pour la communication requête-réponse HTTP et pour l'échange de messages asynchrones propagés via un courtier de messages. Les tests doivent aider à garantir que les formats de message sont pris en charge pour garantir un chemin système positif., et les messages mal formatés sont rejetés, et avec des explications suffisantes (et pas seulement avec une erreur "mauvais message").



Test de l'intégration continue et du déploiement continu



Des processus d'intégration continue et de déploiement continus (CI / CD) bien organisés sont essentiels dans tout paradigme de développement logiciel, mais lorsqu'il s'agit d'applications de microservices, un processus CI / CD efficace, précis et rapide est essentiel. Les MOA peuvent être révisés à un rythme de centaines de mises à jour par jour, de sorte qu'un seul microservice dont la construction est tardive peut devenir un goulot d'étranglement et ralentir l'ensemble du processus de publication.



La meilleure façon de jouer la sécurité est de donner aux tests de pipeline CI / CD la même priorité que tout autre mode de test de haut niveau. L'identification et la résolution de problèmes tels que la lenteur des microservices dus à des artefacts dans le code, la lenteur du provisionnement des environnements d'exécution où les microservices sont hébergés et la lente montée en puissance des microservices déjà déployés sont des conditions préalables pour un pipeline CI / CD sain. Même si le microservice est aussi complexe qu'une navette, il sera de peu d'utilité si vous ne pouvez pas déployer et déployer rapidement des unités opérationnelles.



Conclusion



Les microservices sont le vrai joker. Les applications orientées microservices offrent la flexibilité et la vitesse nécessaires pour mettre en ligne de nouvelles fonctionnalités à une vitesse presque fulgurante. Les grandes entreprises qui prennent en charge des millions d'utilisateurs l'ont appris aujourd'hui, mais chaque jour, de plus en plus d'entreprises adoptent ce style architectural lorsque leurs applications atteignent l'échelle de l'ensemble du Web.



Alors que de nombreuses entreprises tentent sérieusement d'incorporer l'esprit d'une architecture orientée microservices dans leurs processus de développement, ces MOA sont souvent testés à l'aide de pratiques initialement destinées à des applications monolithiques. C'est une approche à courte vue.

Au contraire, les entreprises doivent apprendre des techniques de test modernes conçues pour garantir l'indépendance des microservices et l'agilité des applications qui utilisent ces microservices. Lorsque les équipes de développement et les testeurs parviennent à synchroniser les principes de conception des applications de microservices, toute l'entreprise peut s'appuyer davantage sur les atouts des microservices.



All Articles