Compartir a través de


Patrón de disyuntor

El patrón Circuit Breaker ayuda a controlar los errores que pueden tardar diferentes cantidades de tiempo en recuperarse cuando una aplicación se conecta a un servicio remoto o recurso. Un disyuntor bloquea temporalmente el acceso a un servicio defectuoso después de detectar errores. Esta acción evita intentos repetidos incorrectos para que el sistema pueda recuperarse de forma eficaz. Este patrón puede mejorar la estabilidad y la resistencia de una aplicación.

Contexto y problema

En un entorno distribuido, las llamadas a recursos y servicios remotos pueden producir un error debido a errores transitorios. Los errores transitorios incluyen recursos sobrecommitidos o temporalmente no disponibles, conexiones de red lentas o tiempos de espera. Estos errores suelen corregirse después de un breve período de tiempo. Para ayudar a gestionar estos errores, debe diseñar una aplicación en la nube para utilizar una estrategia, como el uso del patrón de reintento .

Los eventos imprevistos pueden crear errores que tardan más tiempo en corregirse. Estos errores pueden variar en gravedad a partir de una pérdida parcial de conectividad a un error de servicio completo. En estas situaciones, una aplicación no debe reintentar continuamente una operación que no es probable que se realice correctamente. En su lugar, la aplicación debe reconocer rápidamente la operación con errores y controlar el error en consecuencia.

Si un servicio está ocupado, un error en una parte del sistema podría provocar errores en cascada. Por ejemplo, puede configurar una operación que invoque un servicio para implementar un tiempo de espera. Si el servicio no responde en este período, la operación responde con un mensaje de error.

Sin embargo, esta estrategia puede bloquear las solicitudes simultáneas a la misma operación hasta que expire el período de tiempo de espera. Estas solicitudes bloqueadas pueden contener recursos críticos del sistema, como memoria, subprocesos y conexiones de base de datos. Este problema puede agotar los recursos, lo que podría producir un error en otras partes no relacionadas del sistema que necesitan usar los mismos recursos.

En estas situaciones, una operación debe fallar inmediatamente y solo intentar invocar el servicio si es probable que tenga éxito. Para resolver este problema, establezca un tiempo de espera más corto. Pero asegúrese de que el tiempo de espera es suficiente para que la operación se realice correctamente la mayor parte del tiempo.

Solución

El patrón Circuit Breaker ayuda a evitar que una aplicación intente ejecutar repetidamente una operación que probablemente produzca un error. Este patrón permite que la aplicación siga ejecutándose sin esperar a que el error se corriga o se desperdiga ciclos de CPU al determinar que el error es persistente. El patrón Circuit Breaker también permite a una aplicación detectar cuándo se resuelve el error. Si se resuelve el error, la aplicación puede intentar invocar la operación de nuevo.

Nota:

El patrón Circuit Breaker tiene un propósito diferente al patrón Retry. El patrón Retry permite a una aplicación reintentar una operación con la expectativa de que finalmente se realice correctamente. El patrón Circuit Breaker impide que una aplicación realice una operación que probablemente produzca un error. Una aplicación puede combinar estos dos patrones usando Retry para invocar una operación a través de un disyuntor. Sin embargo, la lógica de reintento debe ser sensible a las excepciones que devuelve el disyuntor y detener los reintentos si el disyuntor indica que un error no es transitorio.

Un disyuntor actúa como un intermediario para las operaciones que podrían fallar. El proxy debe supervisar el número de errores recientes y usar esta información para decidir si se debe permitir que la operación continúe o devuelva inmediatamente una excepción.

Puede implementar el proxy como una máquina de estado que incluya los estados siguientes. Estos estados imitan la funcionalidad de un interruptor eléctrico:

  • Cerrado: la solicitud de la aplicación se enruta a la operación. El proxy mantiene un recuento del número de errores recientes. Si la llamada a la operación falla, el proxy incrementa este recuento. Si el número de fallos recientes supera un umbral especificado en un periodo de tiempo determinado, el proxy pasa al estado Abierto e inicia un temporizador de tiempo de espera. Cuando el temporizador expira, el proxy pasa al estado Semiabierto.

    Nota:

    Durante el tiempo de espera, el sistema intenta corregir el problema que provocó el error antes de permitir que la aplicación vuelva a intentar la operación.

  • Abierto: la solicitud de la aplicación produce un error inmediatamente y se devuelve una excepción a la aplicación.

  • Semiabierto: se permite pasar un número limitado de solicitudes de la aplicación e invocar la operación. Si estas solicitudes se realizan correctamente, el disyuntor supone que el error que provocó el error se ha corregido y el disyuntor cambia al estado Closed. Se restablece el contador de errores. Si se produce un error en alguna solicitud, el disyuntor supone que el error sigue presente, por lo que se revierte al estado abierto. Reinicia el temporizador de tiempo de espera para que el sistema pueda recuperarse del error.

    Nota:

    El estado Semiabierto ayuda a evitar que un servicio en recuperación se vea inundado repentinamente de peticiones. Como servicio se recupera, es posible que pueda admitir un volumen limitado de solicitudes hasta que se complete la recuperación. Pero mientras la recuperación está en curso, una avalancha de trabajo puede hacer que el servicio se agote o falle de nuevo.

El siguiente diagrama muestra las operaciones del contador para cada estado.

Diagrama que muestra los estados del disyuntor.

El contador de fallos para el estado Cerrado se basa en el tiempo. Se restablece automáticamente a intervalos periódicos. Este diseño ayuda a evitar que el disyuntor entre en el estado Abrir si experimenta errores ocasionales. El umbral de error desencadena el estado Open solo cuando se produce un número especificado de errores durante un intervalo especificado.

El contador de éxito para el estado Semiabierto registra el número de intentos exitosos para invocar la operación. El disyuntor vuelve al estado Cerrado después de un número determinado de invocaciones de operaciones consecutivas con éxito. Si se produce un error en alguna invocación, el disyuntor entra en el estado Abierto inmediatamente y el contador de éxito se restablece la próxima vez que entra en el estado Medio Abierto.

Nota:

La recuperación del sistema se basa en operaciones externas, como restaurar o reiniciar un componente con errores o reparar una conexión de red.

El patrón Circuit Breaker proporciona estabilidad mientras el sistema se recupera de un error y minimiza el impacto en el rendimiento. Puede ayudar a mantener el tiempo de respuesta del sistema. Este patrón rechaza rápidamente una solicitud de una operación que es probable que falle, en lugar de esperar a que la operación agote el tiempo de espera o nunca regrese. Si el disyuntor genera un evento cada vez que cambia el estado, esta información puede ayudar a supervisar el estado del componente del sistema protegido o a alertar a un administrador cuando un interruptor cambia al estado Open.

Puede personalizar y adaptar este patrón a diferentes tipos de errores. Por ejemplo, puede aplicar un temporizador de tiempo de espera creciente a un disyuntor. Puede colocar el disyuntor en el estado Abierto durante unos segundos inicialmente. Si el error no se resuelve, aumente el tiempo de espera hasta unos minutos y ajuste en consecuencia. En algunos casos, en lugar de devolver un error y generar una excepción, el estado Open puede devolver un valor predeterminado que sea significativo para la aplicación.

Nota:

Tradicionalmente, los disyuntores se basaban en umbrales preconfigurados, como el recuento de errores y la duración del tiempo de espera. Este enfoque dio lugar a un comportamiento determinista pero a veces poco óptimo.

Las técnicas adaptables que usan inteligencia artificial y aprendizaje automático pueden ajustar dinámicamente los umbrales en función de los patrones de tráfico en tiempo real, las anomalías y las tasas de errores históricos. Este enfoque mejora la resistencia y la eficacia.

Problemas y consideraciones

Tenga en cuenta los siguientes factores al implementar este patrón:

  • Control de excepciones: Una aplicación que invoca una operación a través de un disyuntor debe poder controlar las excepciones si la operación no está disponible. La administración de excepciones se basa en la aplicación. Por ejemplo, una aplicación podría degradar temporalmente su funcionalidad, invocar una operación alternativa para intentar realizar la misma tarea o obtener los mismos datos, o notificar la excepción al usuario y pedirle que vuelva a intentarlo más tarde.

  • Tipos de excepciones: Los motivos de un error de solicitud pueden variar en gravedad. Por ejemplo, una solicitud podría producir un error porque un servicio remoto se bloquea y requiere varios minutos para recuperarse o porque un servicio sobrecargado provoca un tiempo de espera. Un disyuntor podría ser capaz de examinar los tipos de excepciones que se producen y ajustar su estrategia en función de la naturaleza de estas excepciones. Por ejemplo, podría requerir un mayor número de excepciones de tiempo de espera para activar el disyuntor automático al estado Abierto en comparación con el número de fallos causados por el servicio no disponible.

  • Supervisión: un disyuntor debe proporcionar una visibilidad clara de las solicitudes fallidas y exitosas para que los equipos de operaciones puedan evaluar el estado del sistema. Use el seguimiento distribuido para la visibilidad de un extremo a otro en todos los servicios.

  • Capacidad de recuperación: Debe configurar el disyuntor para que coincida con el patrón de recuperación probable de la operación que protege. Por ejemplo, si el disyuntor permanece en el estado Abierto durante un largo período, puede provocar excepciones aunque se resuelva el motivo del fallo. De forma similar, un disyuntor puede fluctuar y reducir los tiempos de respuesta de las aplicaciones si cambia del estado Abierto al estado Medio Abierto demasiado rápido.

  • Pruebas de fallos de operación: En el estado de Open, en lugar de utilizar un temporizador para determinar cuándo cambiar al estado Half-Open, un disyuntor puede realizar un ping periódicamente al servicio o recurso remoto para determinar si está disponible. Este ping puede intentar invocar una operación que falló anteriormente o usar una operación especial de verificación de estado que proporciona el servicio remoto. Para más información, consulte Patrón Health Endpoint Monitoring.

  • Anulación manual: Si el tiempo de recuperación de una operación que falla es extremadamente variable, debe proporcionar una opción de restablecimiento manual que permita a un administrador cerrar un disyuntor y restablecer el contador de fallos. Del mismo modo, un administrador puede forzar un disyuntor en el estado Abrir y reiniciar el temporizador de tiempo de espera si la operación protegida no está disponible temporalmente.

  • Concurrencia: Un gran número de instancias concurrentes de una aplicación puede acceder al mismo disyuntor. La implementación no debe bloquear las solicitudes simultáneas ni agregar una sobrecarga excesiva a cada llamada a una operación.

  • Diferenciación de recursos: Tenga cuidado al usar un único disyuntor para un tipo de recurso si puede haber varios proveedores independientes subyacentes. Por ejemplo, en un almacén de datos que contiene varias particiones, una partición podría ser totalmente accesible mientras que otra experimenta un problema temporal. Si se combinan las respuestas de error en estos escenarios, una aplicación podría intentar acceder a algunas particiones incluso cuando es probable que se produzca un error. Y es posible que se bloquee el acceso a otros fragmentos, aunque es probable que tenga éxito.

  • Interrupción acelerada del circuito: A veces una respuesta de fallo puede contener suficiente información para que el disyuntor se dispare inmediatamente y permanezca disparado durante un tiempo mínimo. Por ejemplo, la respuesta de error de un recurso compartido sobrecargado puede indicar que la aplicación debe intentarlo de nuevo en unos minutos, en lugar de volver a intentarlo inmediatamente.

  • Implementaciones multirregión: Puede diseñar un disyuntor para despliegues de región única o multirregión. Para diseñar implementaciones de varias regiones, use equilibradores de carga globales o estrategias de interrupción de circuitos personalizados compatibles con regiones que ayudan a garantizar la conmutación por error controlada, la optimización de latencia y el cumplimiento normativo.

  • Interruptores de malla de servicios: Los disyuntores se pueden implementar en la capa de aplicación o como una función transversal y abstracta. Por ejemplo, las mallas de servicio a menudo admiten la interrupción de circuitos como sidecar o como una capacidad independiente sin modificar el código de la aplicación.

    Nota:

    Un servicio puede devolver HTTP 429 (demasiadas solicitudes) si limita el cliente o HTTP 503 (servicio no disponible) si el servicio no está disponible. La respuesta puede incluir otra información, como la duración prevista del retraso.

  • Repetición de solicitudes fallidas: En el estado Abierto, en lugar de simplemente fallar rápidamente, un disyuntor también puede registrar los detalles de cada solicitud a un diario y disponer que estas solicitudes se reproduzcan cuando el recurso o servicio remoto esté disponible.

  • Tiempos de espera inadecuados en servicios externos: es posible que un disyuntor no brinde protección completa a las aplicaciones frente a errores en servicios externos que tienen largos tiempos de espera. Si el tiempo de espera es demasiado largo, un subproceso que ejecuta un disyuntor podría bloquearse durante un período prolongado antes de que el disyuntor indique que se produjo un error en la operación. Durante este tiempo, muchas otras instancias de aplicación también pueden intentar invocar el servicio a través del disyuntor y vincular numerosos subprocesos antes de que todos produzcan un error.

  • Adaptabilidad a la diversificación de la computación: Los interruptores de circuito deben tener en cuenta diferentes entornos de computación, desde cargas de trabajo sin servidor hasta en contenedores, donde factores como los arranques en frío y la escalabilidad afectan al manejo de fallos. Los enfoques adaptables pueden ajustar dinámicamente las estrategias en función del tipo de proceso, lo que ayuda a garantizar la resistencia en arquitecturas heterogéneas.

Cuándo usar este patrón

Use este patrón en los siguientes supuestos:

  • Quiere evitar errores en cascada deteniendo llamadas de servicio remoto excesivas o solicitudes de acceso a un recurso compartido si es probable que se produzca un error en estas operaciones.

  • Desea enrutar el tráfico de forma inteligente basándose en señales de fallo en tiempo real para mejorar la capacidad de recuperación multirregión.

  • Quiere protegerse frente a dependencias de baja velocidad y así mantener los objetivos de nivel de servicio y evitar la degradación del rendimiento de los servicios de alta latencia.

  • Quiere administrar problemas de conectividad intermitentes y reducir los errores de solicitud en entornos distribuidos.

Este patrón podría no ser adecuado cuando:

  • Debe administrar el acceso a recursos privados locales en una aplicación, como estructuras de datos en memoria. En este entorno, un disyuntor agrega sobrecarga al sistema.

  • Debe usarlo como sustituto del control de excepciones en la lógica de negocios de las aplicaciones.

  • Los algoritmos de reintento conocidos son suficientes y las dependencias están diseñadas para controlar los mecanismos de reintento. En este escenario, un disyuntor en la aplicación podría agregar complejidad innecesaria al sistema.

  • Esperar a que un disyuntor se restablezca podría presentar retrasos inaceptables.

  • Dispone de una arquitectura basada en mensajes o eventos, ya que a menudo enrutan los mensajes fallidos a una cola de letra muerta para su procesamiento manual o diferido. El aislamiento de errores integrado y los mecanismos de reintento suelen ser suficientes.

  • La recuperación de errores se administra en el nivel de infraestructura o plataforma, como con comprobaciones de estado en equilibradores de carga globales o mallas de servicio.

Diseño de cargas de trabajo

Evalúe cómo utilizar el patrón Circuit Breaker en el diseño de una carga de trabajo para abordar los objetivos y principios cubiertos en los pilares de Marco de arquitectura de Azure. En la tabla siguiente se proporciona una guía sobre cómo este patrón apoya los objetivos de cada pilar.

Fundamento Cómo apoya este patrón los objetivos de los pilares
Las decisiones de diseño de fiabilidad ayudan a que su carga de trabajo sea resiliente a fallos y garantizan que se recupere a un estado de pleno funcionamiento después de que se produzca un fallo. Este patrón ayuda a evitar que una dependencia con errores se sobrecargue. Utiliza este patrón para facilitar una degradación suave en la carga de trabajo. Acoplar disyuntores con recuperación automática para proporcionar autoconservación y autorreparación.

- RE:03 Análisis del modo de error
- errores transitorios
- RE:07 Autopreservación
Eficiencia del rendimiento ayuda a su carga de trabajo a satisfacer eficientemente las demandas mediante optimizaciones en el escalado, los datos y el código. Este patrón evita el enfoque de reintento en error, lo que puede provocar un uso excesivo de recursos durante la recuperación de dependencias y puede sobrecargar el rendimiento en una dependencia que intenta recuperarse.

- PE:07 Código e infraestructura
- PE:11 Respuestas a problemas en tiempo real

Si este patrón introduce concesiones dentro de un pilar, considérelas en relación con los objetivos de los otros pilares.

Ejemplo

Este ejemplo implementa el patrón Circuit Breaker para ayudar a evitar el desbordamiento de cuotas mediante el uso del nivel gratuito de por vida de Azure Cosmos DB. Este nivel es principalmente para datos no críticos y funciona con un plan de capacidad que asigna una cuota específica de unidades de recursos por segundo. Durante los eventos estacionales, la demanda puede exceder la capacidad proporcionada, lo que puede resultar en respuestas de tipo 429.

Cuando se producen picos de demanda, las alertas de Azure Monitor con umbrales dinámicos detectan y notifican proactivamente a los equipos de operaciones y administración que la base de datos necesita más capacidad. Simultáneamente, un disyuntor ajustado mediante patrones de error históricos se activa para evitar fallos en cascada. En este estado, la aplicación se degrada correctamente devolviendo respuestas predeterminadas o almacenadas en caché. La aplicación informa a los usuarios de la falta de disponibilidad temporal de determinados datos al tiempo que conserva la estabilidad general del sistema.

Esta estrategia mejora la resistencia que se alinea con la justificación empresarial. Controla los aumentos de capacidad para que los equipos de cargas de trabajo puedan administrar los aumentos de costos deliberadamente y mantener la calidad del servicio sin aumentar inesperadamente los gastos operativos. Después de que la demanda disminuya o se confirme un aumento en la capacidad, el disyuntor se restablece y la aplicación recupera su funcionalidad completa, alineándose con los objetivos técnicos y presupuestarios.

diagrama que muestra Azure Cosmos DB y una implementación del disyuntor en Azure App Service.

El diagrama tiene tres secciones principales. La primera sección contiene dos iconos del explorador web. El primer icono muestra una interfaz de usuario totalmente funcional y el segundo icono muestra una experiencia de usuario degradada que tiene una advertencia en pantalla para indicar el problema a los usuarios. La segunda sección se incluye dentro de un rectángulo de línea discontinua, que se divide en dos grupos. El grupo superior incluye los recursos de carga de trabajo, App Service y Azure Cosmos DB. Las flechas de ambos iconos del explorador web apuntan a la instancia de App Service, que representa las solicitudes entrantes del cliente. Además, las flechas de la instancia de App Service apuntan a Azure Cosmos DB, lo que indica las interacciones de datos entre los servicios de aplicación y la base de datos. Otra flecha va desde la instancia de App Service hasta sí misma, simbolizando el mecanismo de tiempo de espera del disyuntor. Este bucle significa que, cuando se detecta una respuesta 429 Demasiadas solicitudes, el sistema vuelve a atender las respuestas almacenadas en caché, lo que degrada la experiencia del usuario hasta que se resuelve la situación. El grupo inferior de esta sección se centra en la observabilidad y las alertas. Azure Monitor recopila datos de los recursos de Azure del grupo superior. Azure Monitor también se conecta a un icono que representa una regla de alerta. En la tercera sección se muestra el flujo de trabajo de escalabilidad que se desencadena cuando se genera la alerta. Una flecha conecta el icono de alerta a los aprobadores, lo que indica que la notificación se envía a ellos para su revisión. Otra flecha conduce de los aprobadores a una consola de desarrollo, que simboliza el proceso de aprobación para escalar la base de datos. Por último, una flecha posterior se extiende desde la consola de desarrollo a Azure Cosmos DB, que muestra la acción de escalar la base de datos en respuesta a la condición de sobrecarga.

Descargar un archivo de Visio de esta arquitectura.

Flujo A: estado cerrado

  • El sistema funciona normalmente y todas las solicitudes llegan a la base de datos sin devolver ninguna respuesta HTTP 429.

  • El disyuntor permanece cerrado y no se necesitan respuestas predeterminadas o almacenadas en caché.

Flujo B: estado abierto

  1. Cuando el disyuntor recibe la primera respuesta 429, pasa a un estado Abierto.

  2. Las solicitudes posteriores se cortocircuitan inmediatamente, lo que devuelve respuestas predeterminadas o almacenadas en caché e informa a los usuarios de la degradación temporal. La aplicación está protegida frente a una sobrecarga adicional.

  3. Azure Monitor recibe registros y datos de telemetría y los evalúa con respecto a los umbrales dinámicos. Una alerta se desencadena si se cumplen las condiciones de la regla de alertas.

  4. Un grupo de acciones notifica proactivamente al equipo de operaciones de la condición de sobrecarga.

  5. Después de la aprobación del equipo encargado de la carga de trabajo, el equipo de operaciones puede aumentar la capacidad aprovisionada para aliviar la sobrecarga o retrasar el escalado si la carga disminuye por sí sola.

Flujo C: estado semiabierto

  1. Después de un tiempo de espera predefinido, el disyuntor entra en un estado Semiabierto que permite un número limitado de solicitudes de prueba.

  2. Si estas solicitudes de prueba se realizan correctamente sin devolver 429 respuestas, el interruptor se restablece a un estado Cerrado y las operaciones normales se restauran de nuevo a Flujo A. Si los errores persisten, el interruptor se revierte al estado Abierto o Flujo B.

Componentes

  • Azure App Service hospeda la aplicación web que actúa como punto de entrada principal para las solicitudes de cliente. El código de aplicación implementa la lógica que aplica las directivas del disyuntor y entrega respuestas predeterminadas o almacenadas en caché cuando el circuito está abierto. Esta arquitectura ayuda a evitar sobrecargas en sistemas aguas abajo y a mantener la experiencia del usuario durante la demanda máxima o las fallas.

  • Azure Cosmos DB es uno de los almacenes de datos de la aplicación. Sirve datos no críticos a través del nivel gratis, que es ideal para cargas de trabajo de producción pequeñas. El mecanismo del disyuntor ayuda a limitar el tráfico a la base de datos durante períodos de alta demanda.

  • Azure Monitor funciona como una solución de supervisión centralizada. Agrega todos los registros de actividad para ayudar a garantizar una observabilidad completa de un extremo a otro. Azure Monitor recibe registros y datos de telemetría de App Service y métricas clave de Azure Cosmos DB (como el número de respuestas de 429) para la agregación y el análisis.

  • Las alertas de Azure Monitor comparan las reglas de alerta con umbrales dinámicos para identificar posibles interrupciones basadas en datos históricos. Las alertas predefinidas notifican al equipo de operaciones cuando se infringen los umbrales.

    A veces, el equipo de cargas de trabajo podría aprobar un aumento del rendimiento aprovisionado, pero el equipo de operaciones prevé que el sistema puede recuperarse por sí mismo porque la carga no es demasiado alta. En estos casos, el tiempo de espera del disyuntor transcurre de forma natural. Durante este tiempo, si las respuestas de 429 dejan de funcionar, el cálculo del umbral detecta las interrupciones prolongadas y las excluye del algoritmo de aprendizaje. Como resultado, la próxima vez que se produzca una sobrecarga, el umbral espera una tasa de errores más alta en Azure Cosmos DB, lo que retrasa la notificación. Este ajuste permite que el disyuntor controle el problema sin una alerta inmediata, lo que mejora el costo y la eficiencia operativa.

  • El patrón Reliable Web App aplica el patrón Circuit Breaker a las aplicaciones web que convergen en la nube.

  • El patrón Reintento describe cómo una aplicación puede controlar los errores temporales previstos cuando intenta conectarse a un servicio o recurso de red mediante un reintento transparente de una operación que anteriormente produjo un error.

  • El patrón de Supervisión del punto de conexión de mantenimiento describe cómo un disyuntor puede probar el estado de un servicio enviando una solicitud a un punto final que el servicio expone. El servicio debe devolver información que indique su estado.