Patrón Circuit Breaker en la resiliencia de los microservicios
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 con una adecuada política de reintentos.
Sin embargo puede darse el caso en que no se 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 “ocupada”, el cliente no recibe una respuesta y los recursos de la infraestructura (ram, cpu, entre otros) 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.
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 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 ocasionales se abra el circuito cada cierto tiempo se reinicia. Por lo que sólo se entrará en un estado de abierto si la cantidad de fallas ocurren en un intervalo de tiempo.
La siguiente figura ilustra los estados de operación de Circuit Breaker.
¿Cuándo usar este patrón?
Este patrón siempre debe aplicarse.
Para comprender la necesidad de usar Retry y Circuit Breaker, si aún no lo tienes claro se recomienda leer sobre las falacias de la computación distribuida.
Software recomendado
Resilience4j, Hystrix.
Implementación de Circuit Breaker
Visita el siguiente artículo donde tenemos un ejemplo con Hystrix.
En nuestro libro de microservicios, hablamos de este y otros patrones