Tolerancia a fallos en un cliente de microservicio con Spring Cloud Netflix y Hystrix

Escrito por picodotdev el , actualizado el .
java planeta-codigo programacion
Comentarios

Spring
Java

Los microservicios son independientes unos de otros y se comunican mediante operaciones de red. Dado que las operaciones se realizan a través de un medio no confiable como la red, dada su naturaleza efímera y a que pueden fallar en los microservicios es importante que los clientes estén preparados ante posibles fallos.

Un patrón o técnica que se suele emplear es el de Circuit Breaker, en Java y con Spring se ofrece en el proyecto Spring Cloud Netflix mediante Hystrix y Javanica. Este patrón soluciona dos problemas cuando un microservicio del que se depende falla y hace al microservicio que lo usa tolerante a fallos.

  • Uno es que cuando un microservicio empieza a fallar es necesario dejar de hacerle peticiones para permitirle recuperarse si está saturado que provoca esos fallos. Cuando ocurre un fallo es posible realizar una acción en sustitución de la llamada al microservicio y devolver un valor alternativo como medida paliativa y hacer que el microsevicio afectado tenga la posibilidad de seguir ofreciendo su servicio aunque sea de forma degradada.
  • Otro problema es que el microservicio aunque no falle tarde demasiado en responder, se puede establecer un timeout que si se supera se deja de esperar e igualmente se realiza la acción de sustitución lo que evita que los microservicios que usan uno que tarda demasiado en responder agoten sus recursos y empiecen a fallar o tardar demasiado también.

En ambos casos se evita que la cadena de microservicios empiece a fallar y con ello sistema completo.

El patrón circuit breaker se denomina así ya que implementa una lógica similar a un circuito eléctrico. El circuito en su estado normal está cerrado y se realizan las llamadas al microservicio servidor. Si el microservicio servidor empieza a fallar se llama a la acción alternativa con su valor, si se supera un umbral de errores el circuito pasa a estado abierto y se dejan de hacer llamadas al microservicio servidor. Cada cierto tiempo definido se realiza una llamada al servicio servidor para comprobar su estado de forma que si responde correctamente el circuito pasa a estado cerrado nuevamente y las siguientes llamadas se realizan al microservicio servidor dejándose de utilizar la acción alternativa.

Diagrama del patrón circuit breaker, de estados y método fallback

Para utilizar Hystrix como implementación del patrón circuit breaker en una aplicación Java con Spring Boot el método que realiza la llamada al microservicio servidor ha de encapsularse en un método anotado con la anotación @HystrixCommand, como parámetro se indica un método con la acción alternativa o fallback que obtiene un valor en los fallos. También se puede indicar el tiemout de espera antes de considerar que la llamada ha fallado con la propiedad execution.isolation.thread.timeoutInMilliseconds. Igualmente se pueden indicar los valores para abrir el circuito con circuitBreaker.requestVolumeThreshold y circuitBreaker.errorThresholdPercentage. Esos son los básicos para utilizar este patrón de tolerancia a fallos. Tiene algunos valores adicionales más que se pueden configurar para adaptar el patrón a los valores óptimos de la aplicación.

En el ejemplo el cliente en un bucle realiza las llamadas al servicio con un método get() anotado con @HystrixCommand. En este método se encapsula la petición HTTP que puede fallar, utilizando la librería Jersey y obtenida la ubicación de una instancia del servicio a su vez del servicio de registro y descubrimiento Eureka.

El circuito se abre cuando el número de llamadas supera un umbral y un porcentaje de fallos, se han de cumplir las dos condiciones. Si el número de llamadas que se realizan no superan el umbral aunque todas fallen el circuito permanece cerrado. Ambos valores son personalizables con las propiedades circuitBreaker.requestVolumeThreshold y circuitBreaker.errorThresholdPercentage. El circuito permanece abierto al menos durante el tiempo indicado por metrics.rollingStats.timeInMilliseconds.

En la aplicación ejemplo hay un microservicio servidor y un microservicio cliente, iniciada una instancia de microservicio servidor y una instancia del microservicio cliente que implementa el patrón circuit breaker inicialmente las peticiones se realizarán correctamente si no ocurre un timeout. Si se finaliza el proceso del microservicio servidor las peticiones del cliente al servidor empezarán a fallar y este obtiene el valor alternativo del método fallback, si se supera el umbral de llamadas y de fallos el circuito pasa a estado abierto. Mientras el circuito permanezca abierto el cliente sondea con una petición cada cierto tiempo el estado del servidor, si el servicio servidor se inicia unos instantes después de que esté disponible el cliente con la petición de sondeo comprobará que el servidor funciona, se cerrará el circuito y el cliente empezará a obtener los valores devueltos por el microservicio servidor.

Para monitorizar en tiempo real el estado del sistema y de los circuitos se ofrece un dashboard en el que visualizan el número de peticiones que se están realizando, las fallidas, el estado de los circuitos, las que fallan por timeout o las que fallan con error. Para tener acceso a esta página hay que incluir la dependencia org.springframework.cloud:spring-cloud-starter-netflix-hystrix-dashboard. La página dashboard está disponible en la dirección http://localhost:8085/hystrix.

Estados del circuit breaker

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradle-run.sh.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradle-run.sh.