Circuit Breaker pattern

La llegada de nuevas arquitecturas como SOA o Microservicios han traído grandes ventajas, pero con ello, han surgido nuevas problemáticas que pocas veces se sabe cómo resolver con precisión, uno de estos casos, es identificar cuando un servicio ha dejado de funcionar para dejarle de enviar peticiones, pero por otro lado, identificar el fallo, reportarlo y hacer algo en consecuencia, por suerte, la patrón Circuit Breaker (Corto circuito) permite cerrar la comunicación con un determinado servicio cuando se ha detectado que está fallado.

 

El patrón Circuit Breaker es muy parecido a un fusible, el cual se funde para evitar que una descarga eléctrica afecte al circuito, con la única diferencia de que el software, este fusible se puede restaurar cuando el problema allá pasado. Esto puede resultar un poco confuso, pero analicemos cómo funciona el patrón con el siguiente diagrama:

Circuit Breaker pattern diagrama de sequencia

 

Antes de explicar cómo funciona el diagrama, debemos de comprender que son y el rol que tiene cada uno de los componentes involucrados:

  • Client: representa al cliente que intenta consumir los servicios del Supplier, sin embargo, este lo hace por medio del Circuit Breaker.
  • Circuit Breaker: es el componente que se encarga de la comunicación con el Supplier, el cual, mantiene un registro del estado de salud del servicio que usará para abrir el circuito cuando detecte que el Supplier está fallando.
  • Supplier: representa el servicio de negocio remoto, el cual expone una serie de funcionalidad para ser consumida por el Client.

Una vez que entendemos esto, pasemos a explicar cómo funciona el patrón Circuit Breaker:

  1. El Client realiza una primera llamada al Supplier por medio del Circuit Breaker.
    1. El Circuit Breaker determina que el servicio está operando correctamente el Supplier y redirecciona la petición al Supplier.
    2. El Supplier responde correctamente y envía la respuesta al Circuit Breaker para que sea este quien finalmente reenvíe la respuesta al Client.
  2. El Client envía nuevamente una petición al Supplier por medio del Circuit Breaker
    1. El Circuit Breaker redirecciona la petición al Supplier
    2. En esta ocasión el Supplier responde con error o lanza un Timeout
    3. El Circuit Breaker recibe la respuesta de error y toma nota del error, el cual tiene un contado que determina cuantas veces ha fallado el Supplier de forma simultánea. En este caso, el contado de errores se establece en 1.
    4. El Circuit Breaker redirecciona el error al Client.
  3. Seguido de un tiempo, el Client envía nuevamente una petición al Supplier por medio el Circuit Breaker.
    1. El Circuit Breaker redirecciona la petición al Supplier
    2. El Supplier nuevamente responde con error o Timeout
    3. El Circuit Breaker recibe la respuesta de error e incrementa el contado de errores en 2.
      1. Dada una configuración, el Circuit Breaker puede determinar que 2 es el número máximo de errores simultáneos que puede tolerar antes de realiza el corto circuito y abre el circuito con el Supplier.
      2. Un paso opcional pero muy deseable es tener algún componente de monitoreo que permite notificar a los administradores en tiempo real sobre los errores para poder tomar cartas en el asunto.
    4. El Circuit Breaker redirecciona el error al Client.
  4. El Client nuevamente envía una nueva petición al Supplier por medio del Circuit Breaker.
    1. El Circuit Breaker determina el servicio no está respondiendo debido a los dos errores anteriores, por lo que retorna un error al Client indicándole que el Supplier está fuera de servicio.

 

Como podemos observar en la explicación anterior, el Circuit Breaker puede determinar que un determinado servicio (Supplier) está fuera de servicio al detectar que ha respondido con error de forma consecutiva un número determinado de veces.

 

NOTA: es común confundirse con el termino abierto y cerrado, pues podemos pensar que el estado abierto es cuando el servicio está disponible, sin embargo, como estamos utilizando la nomenclatura de los circuitos eléctricos, por lo que un circuito cerrado es cuando la electricidad flujo, por lo tanto, en este patrón, cerrado significa que existe comunicación con el Supplier.

 

 

Abriendo el circuito

En este punto te estarás preguntando, bien, ya he abierto el circuito, pero no me puedo quedar todo el tiempo así, necesito cerrarlo nuevamente una vez que el problema se ha resuelto. Pues bien, para eso, tenemos una funcionalidad adicional, en la cual configuramos cuanto tiempo debe esperar el Circuit Breaker antes de mandar una solicitud al Supplier. En este caso, por ejemplo, podríamos esperar una hora desde que se cerró el circuito para enviar una nueva petición, si esta petición retorna exitosamente, el Circuit Breaker cerrará nuevamente el circuito con el Supplier, pero, por el contrario, si este nuevamente retorna con error o Timeout, entonces el tiempo de espera se reiniciará y esperará otra hora antes de mandar una nueva petición para comprobar su disponibilidad.

Circuit Breaker pattern Diagrama de secuencia abierto

 

Dicho lo anterior, veamos cómo quedaría el diagrama de secuencia para la reapertura del circuito:

  1. En la parte superior partimos del escenario donde hemos abierto el circuito, lo cual explicamos anteriormente, por lo que nos saltaremos esta explicación. Solo asumamos que, en este punto, el circuito se encuentra abierto.
  2. Una hora después de que el circuito se abrió, el Circuit Breaker redirecciona la siguiente petición al Supplier que estaba fallando para comprobar si ya se encuentra en funcionamiento.
    1. Tras redireccionar la petición al Supplier, este falla nuevamente y redirecciona el error al Circuit Breaker.
    2. El Circuit Breaker al darse cuenta que sigue fallando, reinicia el contador para esperar otra hora antes de volver a intentar consumir los servicios del Supplier.
  3. Tras una hora desde el paso anterior, el Circuit Breaker redirecciona una nueva petición al Supplier para comprobar si ya se encuentra en funcionamiento.
    1. En este caso, el Supplier ya se encuentra operando correctamente, por lo que recibe la petición, la procesa y retornar exitosamente.
    2. El Circuit Breaker detecta la respuesta exitosa del Supplier y cierra nuevamente el circuito.

 

 

Circuit Breaker y los microservicios

En este punto ya hemos aprendido como es que el patrón Circuit Breaker abre el circuito ante una serie de errores consecutivos y como el circuito se cierra cuando el error es resuelto, pero hay algo de lo que no hemos hablado. ¿Te has preguntado que va a pasar con la aplicación si se abre el circuito? Es decir, una hora sin poder lanzar peticiones al Supplier podría causar un caos en nuestra aplicación, pues no podremos hacer nada hasta que el circuito sea restaurado.

Pues bien, te tengo buenas noticias, este patrón no fue diseñado para aplicaciones Standalone, si no que fue diseñado para arquitecturas cloud, donde tenemos alta disponibilidad y escalamiento, lo que quiere decir que debemos de tener múltiples instancias del Supplier, para asegurarnos de seguir operando ante la falla de una o múltiples instancias del mismo Supplier:

Circuit Breaker pattern arquitectura

 

En la imagen anterior ya podemos observar cómo es que existe una serie de instancias de un mismo Supplier, por lo que en caso de que alguno falle, el Circuit Breaker deberá ser lo suficientemente inteligente para redireccionar la petición a otro Supplier en caso de que el primero falle, de esta forma, no retornamos el error al cliente, si no que reintentamos la ejecución en el siguiente Supplier disponible.

 

 

Ciclo de vida del Circuit Breaker

El Circuit Breaker se puede implementar como máquina de estados, la cual puede pasar por 3 estados diferentes, y cada estado afectará la forma en que funciona, los estados son:

  • Closed: Este estado indica que el servicio destino está respondiendo correctamente. En caso de alcanzar un umbral de errores, pasará al estado Open.
  • Open: Este estado indica que el servicio destino está fallando, por lo que toda invocación regresara un error de inmediato. Tras un tiempo de espera, pasará a estado Half-Open.
  • Half-Open (medio abierto): Tras un tiempo en estado Open, el componente pase a Half-Open, lo que indica que puede recibir una pequeña cantidad de solicitudes para validar si el servicio está nuevamente activo. Si las solicitudes pasan exitosamente, el componente pasa a Closed, en otro caso, regresa a Open.

Circuit Breaker pattern life cycle

 

Entornos Asíncronos

Hasta este punto hemos analizado como es que este patrón se utiliza para servicios donde las invocaciones son síncronas, pero ¿qué pasaría si pasamos a un entorno donde los servicios a consumir se ejecutan de forma asíncrona? Por suerte, este patrón también se puede utilizar bajo estas circunstancias, aun que debemos de cambiar un poco la lógica, aunque el principio es el mismo.

En entornos síncronos, no tendremos respuestas con error ni timeout, por lo que las métricas que utilizábamos anteriormente no aplican, es por ello que podemos utilizar Colas (Queues):

Circuit Breaker pattern life cycle asincrono

 

En este caso, el Circuit Breaker en lugar de ejecutar directamente el servicio, tendrá que depositarlo en una Queue, de tal forma que el Supplier los podrá ir tomando a como pueda, lo que impide que lo saturemos de peticiones y lo hagamos colapsar, por otro lado, el Circuit Breaker podrá determinar el número de mensajes que tiene la Queue, y si este alcanza un umbral determinado, podríamos determinar que está fallando o que está procesando los mensajes demasiado lento, por lo que abrimos el circuito para impedir que se sature.

Como vemos, el funcionamiento es el mismo, lo que cambia es la forma de medir si un servicio está fallando o tarda mucho tiempo en procesar los mensajes.

 

¿Te gustaría aprender más patrones como este? te invito a que veas mi libro “Introducción a los patrones de diseño” el único libro que te enseña los principales patrones de diseño utilizando ejemplos del mundo real. Olvídate de aprender con los ejemplos típicos de internet como, crear una pizza, animales que ladren o figuras geométricas.

 

Ventajas de implementar Circuit Breaker

Adicional a las ventajas obvias que podemos ver, como la tolerancia a fallas y el envío de solicitudes a servicios que sabemos que van a fallar, existen otros tipos de ventajas:

 

Monitoreo:

Dado que tenemos un componente que su única funcionalidad es sondear el estado de vida de los servicios, es posible tener un monitoreo en tiempo real, que nos indique los tiempos de respuesta promedio, frecuencia de falla, estado actual del servicio y, sobre todo, notificaciones en tiempo real si algún servicio comienza a fallar.

 

Sobrecarga:

La capacidad de abrir el circuito ante un error o Timeout que sabemos que va a pasar, nos ahorra el hecho de tener muchos hilos esperando a que el servicio responda, y más aún, si tenemos miles de usuarios, es probable tener muchísimos hilos detenidos, lo que provocaría que nuestro sistema se sobre cargue, incluso, puede provocar una bola de nieve que comience a afectar a otros componentes.

 

Tolerancia a fallas

Como ya lo dijimos, el Circuit Breaker puede redireccionar la petición al siguiente Supplier en caso de que alguno falle, evitando tener que enviarle el error al cliente.

 

 

Conclusiones

Como hemos analizado a lo largo de este artículo, utilizar el patrón Circuit Breaker permite que inundemos nuestra aplicación con una gran cantidad de solicitudes que sabemos de antemano que van a fallar, por lo que, en lugar de eso, re direccionamos las peticiones a una instancia del servicio que está operativo.

Este patrón de diseño es altamente utilizado en entornos distribuidos y con arquitecturas de microservicios, por lo que no es para nada recomendable utilizarlo para operaciones en memoria o servicios albergados de forma local. Recordemos que este patrón está diseñado para recursos remotos.

 

3 thoughts to “Circuit Breaker pattern”

  1. Hola, buen día..soy un seguidor de tu blog… y he aprendido muchas cosas…a parte de que lo he recomendado a algunos de mi colegas—

    Tengo una consulta, sobre el circuit breaker…..entiendo el caso de que indicas de que si no esta disponible el Recurso Externo_1…. el patron lo pasará al RecursoExterno2… y así puede crecer…

    Pero en mi caso tengo el escenario…de que el recurso externo es una empresa del Estado que expone un servicio y debo de consumirlo…..y el que tiene problemas el servicio externo de dicha empresa del Estado….alli no puedo hacer lo de RecursoExterno1…RecursoExtertno2….porque el recurso externo es uno solo…

    Igual puedo aplicar este patron con este escenario… ??

    De antemano gracias

    1. Hola Wilson, desde luego, que solo exista una sola instancia de un servicio también es aplicable para usar el Circuit Breaker. Lo puede utilizar para crear una lógica alternativa cuando se habrá el circuito, de esta forma, en lugar de fallar repetidas veces, abres el circuito y realizas una operación alternativa, algo así como un plan B para no denegar el servicio a los usuarios o dar reversa a una transacción.
      saludos.

  2. Aqui falta mencionar la tecnica del suplier en estado open no es solo reemplazarlo. Hay 3 técnicas a tener en cuenta
    1 cacheo
    2 fallback
    3 recover

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *