Implémenter un Fallback avec API Gateway

November 10, 2023

Technology

La résilience des API est la capacité d'une API à échouer rapidement ou à continuer de fonctionner après un échec face à un trafic élevé ou à des défaillances partielles du système. Cela implique la mise en œuvre de modèles de conception courants pour la résilience des API tels que les nouvelles tentatives, les délais d'attente, les disjoncteurs, le basculement et les solutions de repli. Un repli utilisant une passerelle API est un plan B pour une API - lorsque le service API principal échoue, la passerelle API peut rediriger le trafic vers un service secondaire ou renvoyer une réponse prédéfinie. Dans cet article, nous explorerons les défis des techniques de repli existantes et comment les implémenter efficacement en utilisant la passerelle API APISIX.

Repli à la passerelle APISIX

Implémentation des replis avec APISIX

Pour implémenter un mécanisme de repli avec APISIX, vous pouvez utiliser sa fonctionnalité intégrée de priorités des montants ou utiliser un plugin response-rewrite pour renvoyer une réponse prédéfinie lorsqu'un appel de service échoue. Voici un exemple étape par étape pour configurer les deux méthodes de repli.

Prérequis

Ce guide suppose que les outils suivants sont installés localement :

  • Avant de commencer, il est bon d'avoir une compréhension de base d'APISIX. Une familiarité avec la passerelle API, et ses concepts clés tels que les routes, les montants, l'API Admin, les plugins, et le protocole HTTP sera également bénéfique.
  • Docker est utilisé pour installer etcd et APISIX conteneurisés.
  • Installez cURL pour envoyer des requêtes aux services pour validation.

Démarrer le projet Docker APISIX

Ce projet utilise le fichier de configuration Docker Compose prédéfini pour configurer, déployer et exécuter APISIX, etcd, Prometheus et d'autres services avec une seule commande. Tout d'abord, clonez le dépôt apisix-docker sur GitHub, ouvrez-le dans votre éditeur préféré, naviguez vers le dossier example, et démarrez le projet en exécutant simplement la commande docker compose up dans un terminal depuis le dossier racine du projet.

Lorsque vous démarrez le projet, Docker télécharge les images nécessaires pour l'exécution. Il exécute également deux services backend exemple web1 et web2. Vous pouvez voir la liste complète des services dans le fichier docker-compose.yaml.

Repli avec les priorités des montants APISIX activées

Vous pouvez configurer chaque nœud de montant avec un certain niveau de priorité. Lorsque le point de terminaison du nœud avec la priorité la plus élevée échoue, la passerelle API peut rediriger le trafic vers un nœud secondaire avec une priorité inférieure. La priorité par défaut pour tous les nœuds est 0, les nœuds avec une priorité négative peuvent être configurés comme sauvegarde.

Repli avec les priorités des montants APISIX activées

Créez une route vers les deux services et configurez l'attribut de priorité pour chaque nœud de service de montant :

curl "http://127.0.0.1:9180/apisix/admin/routes" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
   "id":"backend-service-route",
   "methods":[
      "GET"
   ],
   "uri":"/get",
   "upstream":{
      "nodes":[
         {
            "host":"web1",
            "port":80,
            "weight":1,
            "priority":0
         },
         {
            "host":"web2",
            "port":80,
            "weight":1,
            "priority":-1
         }
      ]
   }
}'
  • methods : Cela spécifie la méthode HTTP que cette route correspondra. Dans ce cas, elle est configurée pour correspondre aux requêtes GET.
  • uri : C'est le chemin que la route correspondra. Ainsi, toute requête GET vers /get sera gérée par cette route.
  • nodes : C'est un tableau de serveurs backend. Chaque objet du tableau représente un serveur avec son host, port et weight. Le weight est utilisé pour l'équilibrage de charge ; dans ce cas, les deux serveurs ont un poids de 1, ce qui signifie généralement qu'ils partagent le trafic de manière égale.
  • priority : C'est une configuration supplémentaire pour les deux nœuds (web1, web2). Le champ priority est utilisé pour déterminer l'ordre de sélection des nœuds. Un nœud avec une priorité inférieure (un nombre négatif plus élevé) ne sera utilisé que si tous les nœuds avec une priorité supérieure (nombres négatifs inférieurs ou nombres positifs) sont indisponibles.

Vérifiez si vous obtenez uniquement une réponse du service web1 lorsque vous envoyez une requête à la route :

curl "http://127.0.0.1:9080/get"

Vous devriez voir une réponse similaire à ce qui suit :

hello web1

Cela signifie que web1 a été exécuté en premier car il fonctionne. Maintenant, arrêtez le conteneur du service web1 pour vérifier si APISIX bascule vers le service web2.

docker container stop example-web1-1

Maintenant, si vous envoyez à nouveau une requête à la route, vous obtiendrez une réponse du service de repli que nous avons spécifié.

curl "http://127.0.0.1:9080/get"
hello web2

Par défaut, cela prend 60 secondes pendant que la requête va d'abord au service un et bascule vers le service deux s'il est indisponible. Vous pouvez également modifier ce temps en définissant l'attribut timeout de l'objet Upstream. Une autre stratégie de repli pourrait être pendant les déploiements. Si une nouvelle version de l'API est boguée, vous pouvez rediriger le trafic vers l'ancienne version qui est en attente en utilisant la fonctionnalité de répartition du trafic d'APISIX. Revenez à la version précédente si la nouvelle version a des problèmes. Cette méthode de repli fonctionne également bien avec les vérifications de santé des montants.

Repli avec le plugin de réécriture de réponse APISIX

Le plugin response-rewrite d'APISIX vous permet de modifier le code d'état de la réponse, le corps et les en-têtes avant de les renvoyer au client. Cela peut être particulièrement utile pour implémenter un mécanisme de repli en fournissant une réponse par défaut lorsque le service de montant échoue.

Repli avec le plugin de réécriture de réponse APISIX

Si vous avez suivi la première approche, redémarrez le conteneur du service web1 dans Docker :

docker container start example-web1-1

Pour utiliser le plugin response-rewrite pour un repli, vous devez le configurer dans une route. Voici un exemple de la façon dont vous pourriez activer le plugin en utilisant une commande curl :

curl "http://127.0.0.1:9180/apisix/admin/routes" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
   "id":"backend-service-route",
   "methods":[
      "GET"
   ],
   "uri":"/get",
   "plugins":{
      "response-rewrite":{
         "status_code":200,
         "body":"{\"message\":\"This is a fallback response when the service is unavailable\"}",
         "vars":[
            [
               "status",
               "==",
               503
            ]
         ]
      }
   },
   "upstream":{
      "nodes":{
         "web1:80":1
      }
   }
}'

Dans l'exemple ci-dessus, nous avons défini un seul service backend (web1:80) vers lequel le trafic doit être dirigé lorsque cette route est correspondante. Si le service de montant (web1:80) répond avec un statut 503 Service Unavailable, le plugin response-rewrite modifiera la réponse pour avoir un statut 200 OK avec un corps JSON personnalisé. Cela crée effectivement une réponse de repli lorsque le service de montant n'est pas disponible.

"vars": [["status", "==", 503]] : Cette condition indique au plugin d'appliquer la réécriture uniquement lorsque le code d'état d'origine de la réponse est 503 Service Unavailable.

Maintenant, si vous envoyez une requête à la route, vous devriez obtenir une réponse modifiée :

curl "http://127.0.0.1:9080/get"

{"message":"This is a fallback response when the service is unavailable"}

Défis de l'implémentation d'un mécanisme de repli

Les replis sont un composant critique d'une conception de système résilient. Cependant, ils peuvent introduire plus de problèmes lorsqu'ils sont mal implémentés. Lorsqu'on discute des stratégies de repli, les défis rencontrés peuvent différer entre les environnements à une seule machine et les systèmes distribués. Examinons-les pour les comprendre avec des exemples et apprendre comment les éviter en utilisant APISIX.

Difficulté à tester la logique de repli

Il est difficile de simuler avec précision les conditions de défaillance de l'application, comme une panne de base de données, dans un contexte à une seule machine. Tester les stratégies de repli dans les systèmes distribués devient encore plus complexe en raison de l'implication de plusieurs machines et services, ce qui rend difficile la reproduction de tous les modes de défaillance possibles. Par exemple, une API sur un serveur local a un repli vers une réponse mise en cache lorsque la base de données est inaccessible. Tester ce scénario nécessite de simuler une panne de base de données, ce qui pourrait ne pas faire partie des tests réguliers, conduisant à un code de repli non testé sous une charge de production réelle.

APISIX peut être configuré pour router le trafic afin de simuler divers scénarios, y compris les conditions de repli. Cela permet un test plus réaliste de la logique de repli dans des conditions contrôlées, garantissant que les services de repli peuvent gérer le trafic de production.

Les replis eux-mêmes peuvent échouer

Si une solution de repli n'est pas aussi résiliente que prévu, elle pourrait échouer sous la charge accrue qui se produit lorsqu'elle est appelée, provoquant une défaillance en cascade. De plus, un repli vers un service moins efficace peut augmenter les temps de réponse et la charge, conduisant potentiellement à un ralentissement ou à une panne à l'échelle du système. Par exemple, une API pourrait avoir un repli pour écrire des journaux dans un système de fichiers local lorsqu'un service de journalisation distant est indisponible. Cela pourrait entraîner des performances plus lentes en raison des opérations d'E/S de fichiers synchrones.

Avec APISIX, vous pouvez prioriser le trafic pour garantir que les requêtes critiques sont traitées en premier. Cela peut empêcher un service de repli d'être submergé et d'aggraver les performances du système.

Les replis ont des risques opérationnels

L'implémentation d'un repli peut introduire de nouveaux points de défaillance, comme une base de données secondaire qui n'est pas synchronisée avec la base de données primaire, entraînant des incohérences de données.

Les fonctionnalités d'observabilité d'APISIX, comme la journalisation, les métriques et le traçage, peuvent surveiller la santé et les performances des services primaires et de repli. Cette surveillance en temps réel peut aider à identifier et à atténuer les risques associés aux stratégies de repli.

Les replis ont des bugs latents et amplifiés

Les chemins de code de repli peuvent contenir des bugs inactifs qui ne se produisent que sous des conditions de défaillance spécifiques, qui pourraient ne pas se produire souvent et sont difficiles à prédire, ce qui pourrait ne pas être découvert pendant des mois ou des années. Par exemple, un mécanisme de repli dans une API qui passe à une méthode d'authentification différente lors d'une panne du service d'identité pourrait contenir un bug qui n'apparaît que lorsque le repli est déclenché, ce qui pourrait être un événement rare.

APISIX prend en charge les tests A/B continus et les déploiements canaris, permettant aux équipes de tester les chemins de repli en production avec un petit pourcentage de trafic. Cette exposition continue peut aider à découvrir des bugs latents avant qu'ils ne deviennent critiques.

Les replis sont rarement exercés

Les mécanismes de repli sont rarement utilisés, donc lorsqu'ils sont déclenchés, ils pourraient ne pas fonctionner comme prévu en raison d'un manque de tests et de mises à jour réguliers. Par exemple, une API qui sert des données géographiques pourrait avoir un repli vers un ensemble de données statiques lorsque la source de données dynamiques est indisponible. Si ce repli est rarement utilisé, il pourrait servir des informations obsolètes lorsqu'il est activé car il n'est pas régulièrement mis à jour ou testé.

D'un autre côté, APISIX permet la configuration du routage dynamique et peut être utilisé pour rediriger périodiquement une partie du trafic vers les services de repli. Cela garantit que les chemins de repli sont exercés régulièrement et restent prêts à l'emploi.

Conclusion

Les replis sont un filet de sécurité lorsque les choses tournent mal avec les API. En utilisant la configuration des montants d'APISIX ou le plugin de réécriture de réponse, les développeurs peuvent fournir des réponses réfléchies et conviviales qui maintiennent le système fonctionnel et la confiance des utilisateurs. La clé est d'anticiper les points de défaillance potentiels et de concevoir des replis qui offrent la meilleure expérience possible dans les circonstances.

Ressources connexes

Share article link