Patrón: Circuit Breaker
En una arquitectura basada en microservicios es común la existencia de problemas transitorios en la comunicación entre los sistemas que comúnmente se resuelven luego de pasar un tiempo, como vimos anteriormente una adecuada política de Reintentos resuelve este tipo de situaciones.
Sin embargo puede darse el caso de que no pueda recuperar la infraestructura, por ejemplo: una instancia caída, una bases de datos con problemas de conexión, un servicio que no responde, conexión de red caída entre instancias, etc; ante estas situaciones no es suficiente con reintentar, puesto que al persistir el error la llamada puede quedarse “colgada”, el cliente no recibe una respuesta y los recursos de la infraestructura (ram, cpu, etc) quedan bloqueados, cuestión que se agrava a medida que se incrementa el número de peticiones al recurso que no está respondiendo.
Este tipo de situaciones se resuelven con la aplicación del patrón Circuit Breaker. Este patrón impide que un sistema realice o continúe realizando peticiones a otro cuya probabilidad de fallo es alta, los patrones Retry y Circuit Breaker se complementan y una aplicación no podrá continuar haciendo reintentos a otra si Circuit Breaker lo indica.
Estados de operación
Circuit breaker funciona similar a un circuito eléctrico y maneja 3 estados que definen si existirá comunicación entre los sistemas o no.
- Cerrado: Cuando el circuito está cerrado la aplicación enrutará la operación hacia su destino, se mantiene un recuento del número de operaciones fallidas más reciente y si la operación actual falla, el contador de operaciones que fallan se incrementará en uno. Cuando el número de operaciones que fallan llegue a un valor umbral la comunicación se interrumpirá colocando el circuito en un estado de Abierto. En este momento se inicia un temporizador que marcará el tiempo que el circuito permanecerá abierto, cuando este tiempo termine, el sistema se colocará en estado Medio Abierto.
- Medio Abierto: En este estado un número limitado de solicitudes podrá pasar ejecutando la operación, si las operaciones se ejecutan satisfactoriamente entonces se asume que el sistema se ha recuperado, el contador de operaciones que fallan se reinicia y se cierra el circuito pasando todo el tráfico. En caso de que fallo en este estado el temporizador se restablece para dar tiempo a que el sistema pueda recuperarse de la falla.
- Abierto: En el estado abierto, como en un circuito eléctrico no fluyen las llamadas a la operación, para evitar que siga fallando no se ejecutarán las llamadas hasta que el tiempo dado para la recuperación se cumpla.
Es importante resaltar que el estado medio abierto es útil para evitar un cúmulo de solicitudes atacando un servicio que -posiblemente- esté en recuperación y evitar así que si se está recuperando se agote y falle nuevamente.
En el patrón, el contador que cuenta las fallas se basa en el tiempo, para evitar que por fallos ocasiones se abra el circuito cada cierto tiempo se resetea. Por lo que sólo se entrará en un estado de abierto si la cantidad de fallas ocurren en un intervalo de tiempo.
Cuando usar este patrón
Cuando en un sistema conformado por microservicios deben realizarse llamada sincronas entre ellos y existe la posibilidad de que alguno falle (siempre hay posibilidad), Ver las falacias de la computación distribuida.
Software recomendado
Resilience4j, Hystrix (actualmente en mantenimiento)
Espero te sea útil este artículo y hayas aprendido sobre este importante patrón.
Buen artículo. Solo un tema, entiendo que para las llamadas asincrónicas también debe usarse circuit breaker (retrofit + project reactor + resilience4j). He usado resilience por un par de años y está bastante bueno, además de Cb y Retry incorpora otros como bulkhead.