Implementar Fallback con API Gateway

Bobur Umurzokov

Bobur Umurzokov

November 10, 2023

Technology

La resiliencia de la API es la capacidad de una API para fallar rápidamente o asegurarse de que continúe funcionando después de un fallo cuando se enfrenta a errores, tráfico elevado o fallos parciales del sistema. Esto implica implementar patrones comunes de diseño de resiliencia de API como reintentos, tiempos de espera, cortacircuitos, conmutación por error y respaldos. Un respaldo utilizando una puerta de enlace de API es un plan B para una API: cuando el servicio principal de la API falla, la puerta de enlace de API puede redirigir el tráfico a un servicio secundario o devolver una respuesta predefinida. En este artículo, exploraremos los desafíos de las técnicas de respaldo existentes y cómo implementarlas de manera eficiente utilizando la puerta de enlace de API APISIX.

Respaldo en la puerta de enlace APISIX

Implementación de respaldos con APISIX

Para implementar un mecanismo de respaldo con APISIX, puedes utilizar su función incorporada de prioridades de upstream o usar un plugin de reescritura de respuesta para devolver una respuesta predefinida cuando falla una llamada de servicio. Aquí tienes un ejemplo paso a paso de cómo configurar ambos métodos de respaldo.

Requisito(s)

Esta guía asume que las siguientes herramientas están instaladas localmente:

  • Antes de comenzar, es bueno tener un conocimiento básico de APISIX. Familiarizarse con puerta de enlace de API, y sus conceptos clave como rutas, upstream, API de administración, plugins, y el protocolo HTTP también será beneficioso.
  • Docker se utiliza para instalar etcd y APISIX en contenedores.
  • Instala cURL para enviar solicitudes a los servicios para su validación.

Iniciar el proyecto Docker de APISIX

Este proyecto aprovecha el archivo de configuración predefinido de Docker Compose para configurar, implementar y ejecutar APISIX, etcd, Prometheus y otros servicios con un solo comando. Primero, clona el repositorio apisix-docker en GitHub, ábrelo en tu editor favorito, navega a la carpeta example e inicia el proyecto simplemente ejecutando el comando docker compose up en una terminal desde la carpeta raíz del proyecto.

Cuando inicias el proyecto, Docker descarga las imágenes necesarias para ejecutarlo. También ejecuta dos servicios backend de ejemplo web1 y web2. Puedes ver la lista completa de servicios en el archivo docker-compose.yaml.

Respaldo con prioridades de upstream de APISIX habilitadas

Puedes configurar cada nodo de upstream con un cierto nivel de prioridad. Cuando el nodo con la prioridad más alta falla, la puerta de enlace de API puede redirigir el tráfico a un nodo secundario con una prioridad más baja. La prioridad predeterminada para todos los nodos es 0, y los nodos con prioridad negativa pueden configurarse como respaldo.

Respaldo con prioridades de upstream de APISIX habilitadas

Crea una ruta a los dos servicios y configura el atributo de prioridad para cada nodo de servicio de upstream:

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: Especifica el método HTTP que coincidirá con esta ruta. En este caso, está configurado para coincidir con solicitudes GET.
  • uri: Es la ruta que coincidirá con la ruta. Por lo tanto, cualquier solicitud GET a /get será manejada por esta ruta.
  • nodes: Es una matriz de servidores backend. Cada objeto en la matriz representa un servidor con su host, port y weight. El weight se utiliza para el balanceo de carga; en este caso, ambos servidores tienen un peso de 1, lo que normalmente significa que compartirán el tráfico por igual.
  • priority: Es una configuración adicional para los dos nodos (web1, web2). El campo priority se utiliza para determinar el orden en que se seleccionan los nodos. Un nodo con una prioridad más baja (un número negativo más alto) se utilizará solo si todos los nodos con prioridad más alta (números negativos más bajos o números positivos) no están disponibles.

Verifica si obtienes solo una respuesta del servicio web1 cuando envías una solicitud a la ruta:

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

Deberías ver una respuesta similar a la siguiente:

hello web1

Esto significa que web1 se ha ejecutado primero ya que está funcionando. Ahora detén el contenedor del servicio web1 para verificar si APISIX recurre al servicio web2.

docker container stop example-web1-1

Ahora, si envías otra solicitud a la ruta, obtendrás una respuesta del servicio de respaldo que especificamos.

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

Por defecto, tarda 60 segundos mientras la solicitud va primero al servicio uno y recurre al servicio dos si no está disponible. También puedes cambiar este tiempo configurando el atributo timeout del objeto Upstream. Otra estrategia de respaldo podría ser durante las versiones. Si una nueva versión de la API tiene errores, puedes redirigir el tráfico a la versión anterior que está en espera utilizando la función de división de tráfico de APISIX. Recurre a la versión anterior si la nueva versión tiene problemas. Este método de respaldo también funciona bien con comprobaciones de salud de Upstream.

Respaldo con el plugin de reescritura de respuesta de APISIX

El plugin de reescritura de respuesta de APISIX te permite modificar el código de estado de la respuesta, el cuerpo y los encabezados antes de devolverla al cliente. Esto puede ser particularmente útil para implementar un mecanismo de respaldo al proporcionar una respuesta predeterminada cuando el servicio de upstream falla.

Respaldo con el plugin de reescritura de respuesta de APISIX

Si seguiste el primer enfoque, vuelve a ejecutar el contenedor del servicio web1 en Docker:

docker container start example-web1-1

Para usar el plugin de reescritura de respuesta para un respaldo, debes configurarlo en una ruta. Aquí tienes un ejemplo de cómo podrías habilitar el plugin usando un comando 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
      }
   }
}'

En el ejemplo anterior, definimos un solo servicio backend (web1:80) al que se debe dirigir el tráfico cuando se coincide con esta ruta. Si el servicio de upstream (web1:80) responde con un estado 503 Servicio no disponible, el plugin de response-rewrite modificará la respuesta para tener un estado 200 OK con un cuerpo JSON personalizado. Esto crea efectivamente una respuesta de respaldo cuando el servicio de upstream no está disponible.

"vars": [["status", "==", 503]]: Esta condición le dice al plugin que aplique la reescritura solo cuando el código de estado original de la respuesta sea 503 Servicio no disponible.

Ahora, si envías una solicitud a la ruta, deberías obtener una respuesta modificada:

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

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

Desafíos de implementar un mecanismo de respaldo

Los respaldos son un componente crítico de un diseño de sistema resiliente. Sin embargo, pueden introducir más problemas cuando se implementan incorrectamente. Al discutir estrategias de respaldo, los desafíos pueden diferir entre entornos de una sola máquina y sistemas distribuidos. Revisémoslos para entenderlos con ejemplos y aprender cómo evitarlos utilizando APISIX.

Dificultad para probar la lógica de respaldo

Es difícil simular con precisión condiciones de fallo de la aplicación, como un fallo de la base de datos, en un contexto de una sola máquina. Probar estrategias de respaldo en sistemas distribuidos se vuelve aún más complejo debido a la participación de múltiples máquinas y servicios, lo que dificulta replicar todos los modos de fallo posibles. Por ejemplo, una API en un servidor local tiene un respaldo a una respuesta en caché cuando la base de datos no está disponible. Probar este escenario requiere simular un tiempo de inactividad de la base de datos, lo que podría no ser parte de las pruebas regulares, lo que lleva a un código de respaldo no probado bajo la carga real de producción.

APISIX puede configurarse para enrutar el tráfico y simular varios escenarios, incluyendo condiciones de respaldo. Esto permite pruebas más realistas de la lógica de respaldo en condiciones controladas, asegurando que los servicios de respaldo puedan manejar el tráfico de producción.

Los respaldos mismos pueden fallar

Si una solución de respaldo no es tan resiliente como se esperaba, podría fallar bajo la carga aumentada que ocurre cuando se activa, causando un fallo en cascada. Además, un respaldo a un servicio menos eficiente puede aumentar los tiempos de respuesta y la carga, lo que podría llevar a una ralentización o interrupción del sistema. Por ejemplo, una API podría tener un respaldo para escribir registros en un sistema de archivos local cuando un servicio de registro remoto no está disponible. Esto podría llevar a un rendimiento más lento debido a operaciones de E/S de archivos sincrónicas.

Con APISIX, puedes priorizar el tráfico para asegurarte de que las solicitudes críticas se procesen primero. Esto puede evitar que un servicio de respaldo se sature y empeore el rendimiento del sistema.

Los respaldos tienen riesgos operativos

Implementar un respaldo podría introducir nuevos puntos de fallo, como una base de datos secundaria que no se mantiene sincronizada con la principal, lo que lleva a inconsistencias de datos.

Las características de observabilidad de APISIX, como el registro, las métricas y el seguimiento, pueden monitorear la salud y el rendimiento de los servicios principales y de respaldo. Este monitoreo en tiempo real puede ayudar a identificar y mitigar los riesgos asociados con las estrategias de respaldo.

Los respaldos tienen errores latentes y amplificados

Las rutas de código de respaldo pueden contener errores inactivos que solo ocurren bajo condiciones de fallo específicas, lo que podría no suceder a menudo y es difícil de predecir, lo que podría no descubrirse durante meses o años. Por ejemplo, un mecanismo de respaldo en una API que cambia a un método de autenticación diferente durante una interrupción del servicio de identidad podría contener un error que solo aparece cuando se activa el respaldo, lo que podría ser un evento raro.

APISIX admite pruebas A/B continuas y lanzamientos canarios, lo que permite a los equipos probar rutas de respaldo en producción con un pequeño porcentaje de tráfico. Esta exposición continua puede ayudar a descubrir errores latentes antes de que se vuelvan críticos.

Los respaldos se ejercen con poca frecuencia

Los mecanismos de respaldo se usan con poca frecuencia, por lo que cuando se activan, podrían no funcionar como se espera debido a la falta de pruebas y actualizaciones regulares. Por ejemplo, una API que sirve datos geográficos podría tener un respaldo a un conjunto de datos estáticos cuando la fuente de datos dinámicos no está disponible. Si este respaldo se usa raramente, podría servir información obsoleta cuando se active porque no se actualiza ni prueba regularmente.

Por otro lado, APISIX permite la configuración de enrutamiento dinámico y puede usarse para redirigir periódicamente una porción del tráfico a los servicios de respaldo. Esto asegura que las rutas de respaldo se ejerciten regularmente y permanezcan listas para su uso.

Conclusión

Los respaldos son una red de seguridad para cuando las cosas salen mal con las API. Al utilizar la configuración de upstream de APISIX o el plugin de reescritura de respuesta, los desarrolladores pueden proporcionar respuestas reflexivas y amigables para el usuario que mantengan el sistema funcional y mantengan la confianza con los usuarios. La clave es anticipar posibles puntos de fallo y diseñar respaldos que proporcionen la mejor experiencia posible bajo las circunstancias.

Recursos relacionados

Tags: