BLOG | NGINX

Création de microservices : Utilisation d'une passerelle API

NGINX-Partie-de-F5-horiz-black-type-RGB
Miniature de Chris Richardson
Chris Richardson
Publié le 15 juin 2015

Rédacteur – Cette série d’articles en sept parties est désormais terminée :

  1. Introduction aux microservices
  2. Création de microservices : Utilisation d'une passerelle API (cet article)
  3. Création de microservices : Communication interprocessus dans une architecture de microservices
  4. Découverte de services dans une architecture de microservices
  5. Gestion des données pilotée par les événements pour les microservices
  6. Choisir une stratégie de déploiement de microservices
  7. Refactorisation d'un monolithe en microservices

Vous pouvez également télécharger l'ensemble complet des articles, ainsi que des informations sur la mise en œuvre de microservices à l'aide de NGINX Plus, sous forme d'ebook – Microservices : De la conception au déploiement . Consultez également la nouvelle page Solutions Microservices .

Le premier article de cette série en sept parties sur la conception, la création et le déploiement de microservices a présenté le modèle d’architecture de microservices. Il a discuté des avantages et des inconvénients de l’utilisation des microservices et de la façon dont, malgré la complexité des microservices, ils constituent généralement le choix idéal pour les applications complexes. Il s’agit du deuxième article de la série et traitera de la création de microservices à l’aide d’une passerelle API.

Lorsque vous choisissez de créer votre application sous la forme d'un ensemble de microservices, vous devez décider comment les clients de votre application interagiront avec les microservices. Avec une application monolithique, il n’existe qu’un seul ensemble de points de terminaison (généralement répliqués et équilibrés en charge). Cependant, dans une architecture de microservices, chaque microservice expose un ensemble de points de terminaison généralement à granularité fine. Dans cet article, nous examinons l’impact de cela sur la communication client-application et proposons une approche qui utilise une passerelle API .

Introduction

Imaginons que vous développez un client mobile natif pour une application de shopping. Il est probable que vous ayez besoin de mettre en place une page de détails de produit, qui affiche des informations sur un produit donné.

Par exemple, le diagramme suivant montre ce que vous verrez lorsque vous faites défiler les détails du produit dans l’application mobile Android d’Amazon.

Éléments indexés de l'application mobile d'Amazon pour Android, tels qu'ils apparaissent sur l'écran d'un téléphone mobile

Même s'il s'agit d'une application pour smartphone, la page de détails du produit affiche de nombreuses informations. Par exemple, non seulement il y a des informations de base sur le produit (telles que le nom, la description et le prix), mais cette page affiche également :

  • Nombre d'articles dans le panier
  • Historique des commandes
  • Avis des clients
  • Avertissement de faible inventaire
  • Options d'expédition
  • Diverses recommandations, y compris d'autres produits avec lesquels ce produit est fréquemment acheté, d'autres produits achetés par les clients qui ont acheté ce produit et d'autres produits consultés par les clients qui ont acheté ce produit
  • Options d'achat alternatives

Lors de l'utilisation d'une architecture d'application monolithique, un client mobile récupérerait ces données en effectuant un seul appel REST ( GET api.company.com/productdetails/productId ) à l'application. Un équilibreur de charge achemine la demande vers l’une des N instances d’application identiques. L’application interrogerait ensuite différentes tables de base de données et renverrait la réponse au client.

En revanche, lors de l’utilisation de l’architecture de microservices, les données affichées sur la page de détails du produit appartiennent à plusieurs microservices. Voici quelques-uns des microservices potentiels qui possèdent les données affichées sur la page de détails du produit d'exemple :

  • Service de panier d'achat – Nombre d'articles dans le panier
  • Service de commande – Historique des commandes
  • Service de catalogue – Informations de base sur le produit, telles que son nom, son image et son prix
  • Service d'évaluation – Avis des clients
  • Service d'inventaire – Avertissement de faible inventaire
  • Service d'expédition – Options d'expédition, délais et coûts tirés séparément de l'API du fournisseur d'expédition
  • Service(s) de recommandation – Articles suggérés

Le client mobile de l'application de commerce électronique a besoin d'un moyen d'accéder aux API RESTful des 7 microservices

Nous devons décider comment le client mobile accède à ces services. Voyons les options.

Communication directe entre le client et le microservice

En théorie, un client pourrait faire des demandes directement à chacun des microservices. Chaque microservice aurait un point de terminaison public ( https:// serviceName .api.company.name ). Cette URL serait mappée à l'équilibreur de charge du microservice, qui répartit les requêtes sur les instances disponibles. Pour récupérer les détails du produit, le client mobile doit effectuer des demandes auprès de chacun des services répertoriés ci-dessus.

Malheureusement, cette option présente des défis et des limites. L’un des problèmes est l’inadéquation entre les besoins du client et les API détaillées exposées par chacun des microservices. Dans cet exemple, le client doit effectuer sept demandes distinctes. Dans des applications plus complexes, il faudra peut-être en fabriquer beaucoup plus. Par exemple, Amazon décrit comment des centaines de services sont impliqués dans le rendu de leur page produit. Même si un client peut effectuer autant de requêtes sur un réseau local, cela serait probablement trop inefficace sur l’Internet public et serait certainement peu pratique sur un réseau mobile. Cette approche rend également le code client beaucoup plus complexe.

Un autre problème avec le client appelant directement les microservices est que certains peuvent utiliser des protocoles qui ne sont pas compatibles avec le Web. Un service peut utiliser le RPC binaire Thrift tandis qu'un autre service peut utiliser le protocole de messagerie AMQP. Aucun des deux protocoles n’est particulièrement adapté aux navigateurs ou aux pare-feu et il est préférable de l’utiliser en interne. Une application doit utiliser des protocoles tels que HTTP et WebSocket en dehors du pare-feu.

Un autre inconvénient de cette approche est qu’elle rend difficile la refactorisation des microservices. Au fil du temps, nous souhaiterons peut-être modifier la manière dont le système est partitionné en services. Par exemple, nous pourrions fusionner deux services ou diviser un service en deux ou plusieurs services. Toutefois, si les clients communiquent directement avec les services, il peut être extrêmement difficile d’effectuer ce type de refactorisation.

En raison de ce type de problèmes, il est rarement judicieux pour les clients de communiquer directement avec les microservices.

Utilisation d'une passerelle API

En général, une bien meilleure approche consiste à utiliser ce que l’on appelle une passerelle API . Une passerelle API est un serveur qui constitue le point d’entrée unique dans le système. Il est similaire au modèle de façade de la conception orientée objet. La passerelle API encapsule l'architecture interne du système et fournit une API adaptée à chaque client. Il peut avoir d’autres responsabilités telles que l’authentification, la surveillance, l’équilibrage de charge, la mise en cache, la mise en forme et la gestion des requêtes et la gestion des réponses statiques.

Le diagramme suivant montre comment une passerelle API s'intègre généralement dans l'architecture :

Une passerelle API permet aux clients mobiles de l'application de commerce électronique d'accéder aux API RESTful de ses 7 microservices

La passerelle API est responsable du routage des requêtes, de la composition et de la traduction du protocole. Toutes les demandes des clients passent d’abord par la passerelle API. Il achemine ensuite les requêtes vers le microservice approprié. La passerelle API gère souvent une requête en invoquant plusieurs microservices et en agrégeant les résultats. Il peut effectuer la traduction entre les protocoles Web tels que HTTP et WebSocket et les protocoles non compatibles avec le Web qui sont utilisés en interne.

La passerelle API peut également fournir à chaque client une API personnalisée. Elle expose généralement une API à granularité grossière pour les clients mobiles. Considérez, par exemple, le scénario des détails du produit. La passerelle API peut fournir un point de terminaison ( /productdetails?productid= xxx ) qui permet à un client mobile de récupérer tous les détails du produit avec une seule requête. La passerelle API gère la demande en invoquant les différents services (informations sur les produits, recommandations, avis, etc.) et en combinant les résultats.

Un excellent exemple de passerelle API est la passerelle API Netflix . Le service de streaming Netflix est disponible sur des centaines de types d’appareils différents, notamment les téléviseurs, les décodeurs, les smartphones, les consoles de jeu, les tablettes, etc. Au départ, Netflix a tenté de fournir une API unique pour son service de streaming. Cependant, ils ont découvert que cela ne fonctionnait pas bien en raison de la diversité des appareils et de leurs besoins uniques. Aujourd’hui, ils utilisent une passerelle API qui fournit une API adaptée à chaque appareil en exécutant un code d’adaptateur spécifique à l’appareil. Un adaptateur gère généralement chaque demande en appelant en moyenne six à sept services back-end. La passerelle API Netflix gère des milliards de requêtes par jour.

Avantages et inconvénients d'une passerelle API

Comme vous pouvez vous y attendre, l’utilisation d’une passerelle API présente à la fois des avantages et des inconvénients. L’un des principaux avantages de l’utilisation d’une passerelle API est qu’elle encapsule la structure interne de l’application. Plutôt que de devoir invoquer des services spécifiques, les clients parlent simplement à la passerelle. L'API Gateway fournit à chaque type de client une API spécifique. Cela réduit le nombre d'allers-retours entre le client et l'application. Cela simplifie également le code client.

L’API Gateway présente également certains inconvénients. Il s’agit d’un autre composant hautement disponible qui doit être développé, déployé et géré. Il existe également un risque que la passerelle API devienne un goulot d’étranglement du développement. Les développeurs doivent mettre à jour la passerelle API afin d’exposer les points de terminaison de chaque microservice. Il est important que le processus de mise à jour de la passerelle API soit aussi léger que possible. Dans le cas contraire, les développeurs seront obligés de faire la queue pour mettre à jour la passerelle. Malgré ces inconvénients, pour la plupart des applications du monde réel, il est judicieux d’utiliser une passerelle API.

Mise en œuvre d'une passerelle API

Maintenant que nous avons examiné les motivations et les compromis liés à l’utilisation d’une passerelle API, examinons les différents problèmes de conception que vous devez prendre en compte.

Performances et évolutivité

Seule une poignée d’entreprises opèrent à l’échelle de Netflix et doivent gérer des milliards de demandes par jour. Cependant, pour la plupart des applications, les performances et l’évolutivité de la passerelle API sont généralement très importantes. Il est donc logique de construire la passerelle API sur une plateforme qui prend en charge les E/S asynchrones et non bloquantes. Il existe une variété de technologies différentes qui peuvent être utilisées pour mettre en œuvre une passerelle API évolutive. Sur la JVM, vous pouvez utiliser l’un des frameworks basés sur NIO tels que Netty, Vertx, Spring Reactor ou JBoss Undertow. Une option non JVM populaire est Node.js, qui est une plateforme construite sur le moteur JavaScript de Chrome. Une autre option est d'utiliser NGINX Plus . NGINX Plus propose un serveur Web et un proxy inverse matures, évolutifs et hautes performances, faciles à déployer, à configurer et à programmer. NGINX Plus peut gérer l’authentification, le contrôle d’accès, les demandes d’équilibrage de charge, la mise en cache des réponses et fournit des contrôles de santé et une surveillance prenant en compte les applications.

Utilisation d'un modèle de programmation réactive

La passerelle API gère certaines requêtes en les acheminant simplement vers le service backend approprié. Il gère d’autres demandes en invoquant plusieurs services backend et en agrégeant les résultats. Pour certaines demandes, comme une demande de détails sur un produit, les demandes adressées aux services back-end sont indépendantes les unes des autres. Afin de minimiser le temps de réponse, la passerelle API doit exécuter des requêtes indépendantes simultanément. Parfois, cependant, il existe des dépendances entre les demandes. La passerelle API devra peut-être d’abord valider la demande en appelant un service d’authentification, avant d’acheminer la demande vers un service back-end. De même, pour récupérer des informations sur les produits de la liste de souhaits d'un client, la passerelle API doit d'abord récupérer le profil du client contenant ces informations, puis récupérer les informations pour chaque produit. Un autre exemple intéressant de composition d'API est la grille vidéo Netflix .

L’écriture de code de composition d’API à l’aide de l’approche de rappel asynchrone traditionnelle vous conduit rapidement à l’enfer du rappel. Le code sera confus, difficile à comprendre et sujet aux erreurs. Une bien meilleure approche consiste à écrire du code API Gateway dans un style déclaratif en utilisant une approche réactive. Les exemples d'abstractions réactives incluent Future en Scala, CompletableFuture en Java 8 et Promise en JavaScript. Il existe également des extensions réactives (également appelées Rx ou ReactiveX), qui ont été initialement développées par Microsoft pour la plate-forme .NET. Netflix a créé RxJava pour la JVM spécifiquement pour l'utiliser dans sa passerelle API. Il existe également RxJS pour JavaScript, qui fonctionne à la fois dans le navigateur et dans Node.js. L’utilisation d’une approche réactive vous permettra d’écrire un code API Gateway simple mais efficace.

Appel de service

Une application basée sur des microservices est un système distribué et doit utiliser un mécanisme de communication interprocessus. Il existe deux styles de communication interprocessus. Une option consiste à utiliser un mécanisme asynchrone basé sur la messagerie. Certaines implémentations utilisent un courtier de messages tel que JMS ou AMQP. D'autres, comme Zeromq, sont sans courtier et les services communiquent directement. L’autre style de communication interprocessus est un mécanisme synchrone tel que HTTP ou Thrift. Un système utilisera généralement des styles asynchrones et synchrones. Il pourrait même utiliser plusieurs implémentations de chaque style. Par conséquent, la passerelle API devra prendre en charge divers mécanismes de communication.

Découverte de services

La passerelle API doit connaître l'emplacement (adresse IP et port) de chaque microservice avec lequel elle communique. Dans une application traditionnelle, vous pourriez probablement câbler les emplacements, mais dans une application de microservices moderne basée sur le cloud, il s’agit d’un problème non trivial. Les services d'infrastructure, tels qu'un courtier de messages, auront généralement un emplacement statique, qui peut être spécifié via des variables d'environnement du système d'exploitation. Cependant, déterminer l’emplacement d’un service d’application n’est pas si simple. Les services d’application ont des emplacements attribués de manière dynamique. De plus, l’ensemble des instances d’un service change de manière dynamique en raison de la mise à l’échelle automatique et des mises à niveau. Par conséquent, la passerelle API, comme tout autre client de service du système, doit utiliser le mécanisme de découverte de service du système : soit la découverte côté serveur , soit la découverte côté client . Un article ultérieur décrira la découverte de services plus en détail. Pour l’instant, il convient de noter que si le système utilise la découverte côté client, la passerelle API doit pouvoir interroger le registre de services , qui est une base de données de toutes les instances de microservices et de leurs emplacements.

Gestion des pannes partielles

Un autre problème que vous devez résoudre lors de la mise en œuvre d’une passerelle API est le problème de défaillance partielle. Ce problème survient dans tous les systèmes distribués chaque fois qu’un service appelle un autre service qui répond lentement ou n’est pas disponible. La passerelle API ne doit jamais se bloquer indéfiniment en attendant un service en aval. Cependant, la manière dont il gère l’échec dépend du scénario spécifique et du service défaillant. Par exemple, si le service de recommandation ne répond pas dans le scénario des détails du produit, la passerelle API doit renvoyer le reste des détails du produit au client, car ils sont toujours utiles à l'utilisateur. Les recommandations pourraient être soit vides, soit remplacées, par exemple, par une liste prédéfinie des dix meilleurs produits. Toutefois, si le service d’informations sur le produit ne répond pas, API Gateway doit renvoyer une erreur au client.

La passerelle API pourrait également renvoyer des données mises en cache si celles-ci étaient disponibles. Par exemple, étant donné que les prix des produits changent rarement, la passerelle API peut renvoyer des données de tarification mises en cache si le service de tarification n'est pas disponible. Les données peuvent être mises en cache par la passerelle API elle-même ou stockées dans un cache externe tel que Redis ou Memcached. En renvoyant des données par défaut ou des données mises en cache, API Gateway garantit que les défaillances du système n'ont pas d'impact sur l'expérience utilisateur.

Netflix Hystrix est une bibliothèque incroyablement utile pour écrire du code qui appelle des services distants. Hystrix expire les appels qui dépassent le seuil spécifié. Il implémente un modèle de disjoncteur , qui empêche le client d’attendre inutilement un service qui ne répond pas. Si le taux d’erreur d’un service dépasse un seuil spécifié, Hystrix déclenche le disjoncteur et toutes les demandes échoueront immédiatement pendant une période de temps spécifiée. Hystrix vous permet de définir une action de secours lorsqu'une requête échoue, comme la lecture à partir d'un cache ou le renvoi d'une valeur par défaut. Si vous utilisez la JVM, vous devriez certainement envisager d'utiliser Hystrix. Et si vous travaillez dans un environnement non JVM, vous devez utiliser une bibliothèque équivalente.

Résumé

Pour la plupart des applications basées sur des microservices, il est judicieux d’implémenter une passerelle API, qui agit comme un point d’entrée unique dans un système. La passerelle API est responsable du routage des requêtes, de la composition et de la traduction du protocole. Elle fournit à chaque client de l'application une API personnalisée. La passerelle API peut également masquer les défaillances des services back-end en renvoyant des données mises en cache ou par défaut. Dans le prochain article de la série, nous examinerons la communication entre les services.

Rédacteur – Cette série d’articles en sept parties est désormais terminée :

  1. Introduction aux microservices
  2. Création de microservices : Utilisation d'une passerelle API (cet article)
  3. Création de microservices : Communication interprocessus dans une architecture de microservices
  4. Découverte de services dans une architecture de microservices
  5. Gestion des données pilotée par les événements pour les microservices
  6. Choisir une stratégie de déploiement de microservices
  7. Refactorisation d'un monolithe en microservices

Vous pouvez également télécharger l'ensemble complet des articles, ainsi que des informations sur la mise en œuvre de microservices à l'aide de NGINX Plus, sous forme d'ebook – Microservices : De la conception au déploiement .

Pour un aperçu détaillé des cas d’utilisation supplémentaires, consultez notre série de blogs en trois parties, Déploiement de NGINX Plus en tant que passerelle API :

  • La partie 1 fournit des instructions de configuration détaillées pour plusieurs cas d’utilisation.
  • La partie 2 étend ces cas d’utilisation et examine une gamme de mesures de protection qui peuvent être appliquées pour protéger et sécuriser les services API back-end en production.
  • La partie 3 explique comment déployer NGINX Plus en tant que passerelle API pour les services gRPC.

Le blogueur invité Chris Richardson est le fondateur du CloudFoundry.com original, un PaaS (Platform as a Service) Java précoce pour Amazon EC2. Il conseille désormais les organisations pour améliorer la manière dont elles développent et déploient des applications. Il blogue également régulièrement sur les microservices sur http://microservices.io .


« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."