Trazabilidad en servicios distribuidos con Sleuth y Zipkin
Escrito por
el .
java
planeta-codigo
Enlace permanente
Comentarios
En un sistema complejo como una arquitectura de microservicios medir los tiempos de respuesta de cada uno de ellos ayuda a identificar si alguno se está comportando de forma anómala. Sleuth permite asignar un identificador global que es compartido por todos los microservicios invocados en la misma transacción, permite exportar los tiempos de respuesta a Zipkin que ofrece un panel web en el que identificar que llamadas se han hecho entre microservicios y cuales han sido sus tiempos de respuesta.
El un sistema basado en microservicios unos servicios depende de otros y se comunican haciendo llamadas entre ellos. Las llamadas entre los servicios son un punto de fallo y problemas que conviene monitorizar para que el conjunto de la aplicación funcione correctamente. Con un número importante de servicios la monitorización y la trazabilidad es una de las funcionalidades de las aplicaciones basadas en microservicios, muchas de estas funcionalidades son proporcionadas de forma específica por una herramienta.
En el caso de trazabilidad en microservicios con Sleuth proporciona un identificador global que permite correlacionar todas las trazas desencadenadas por una petición en los diferentes servicios, con el identificador global de una traza se puede obtener el resto de trazas del mismo servicio. Con el identificador global es posible acceder al registro de trazas y obtener todas las correlacionadas con el identificador global como sería el caso de guardar las trazas en Elasticsearch, Logstash y Kibana. Pero las trazas emitidas por los microservicios no ofrecen métricas de cuánto tiempo ha tardado cada uno de los microservicios en su ejecución en devolver la respuesta y sin nada adicional no permite correlacionar las trazas de un servicio con las trazas del servicio llamado.
Otro aspecto de las llamadas entre los microservicios es medir los tiempos de respuesta y latencia entre los servicios, si un servicio tiene un bajo rendimiento y tarda en responder es posible que produzca errores en los servicios que lo usan, provocando otros errores en el sistema. Para que el mal funcionamiento de un servicio provoque errores en otros los servicios han de estar preparados y admitir tolerancia a fallos con la librería Resilience4j. Micrometer, Prometheus y Grafana son la forma de obtener métricas y monitorizar una aplicación Java con Spring Boot que incluye los tiempos de respuesta de los microservicios.
Zipkin es una herramienta que recolecta las transacciones creadas por Sleuth en la ejecución de los microservicios e información de los tiempos de respuesta de las invocaciones que han intervenido en una transación. Ofrece las dos funcionalidades la recolección de datos y la obtención de los mismos. Tanto la recolección como el almacenamiento ofrecen diferentes herramientas para implementarlo, la recolección puede ser mediante peticiones HTTP, RabbitMQ o Kafka y el almacenamiento en memoria, MySQL, Cassandra o Elasticsearch.
En el ejemplo hay un microservicio que hace de servidor y otro de cliente que se comunican mediante peticiones HTTP con REST. Tanto el microservicio cliente como el microservicio servidor usan Sleuth que genera identificativos globales que permiten correlacionar todas las peticiones entre los diferentes servicios.
Sleuth proporcionar trazabilidad con identificativos globales que podrían ser recuperados a través del sistema de logging centralizado como Elasticsearch, Logstash y Kibana. Usando una librería de logging como Log4j se puede configurar Log4j para que emita en las trazas los identificadores globales.
Ejemplo de microservicio con Spring Boot, Sleuth y Zipkin
En el ejemplo de trazabilidad de microservicios con Sleuth consistía en un servicio implementado con Spring Boot, también tiene un cliente que realiza de forma periódica peticiones al servicio. Ambos tienen Sleuth integrado y en las trazas de la consola en ambos aparece el identificador global traceId de la traza. En este ejemplo se configura Sleuth para que envíe a Zipkin las transacciones de estos dos pequeños microservicios.
Para que Sleuth envíe al servidor las métricas de las llamadas entre los microservicios basta con añadir al proyecto del cliente y microservicio la dependencia spring-cloud-starter-zipkin y configurar el medio de transporte que se utiliza para enviar las métricas al servidor, en este caso mediante peticiones HTTP y la dirección de Zipkin. Esto se configura con las propiedades de Spring Boot spring.zipkin.enabled, spring.zipkin.baseUrl y spring.zipkin.sender.type.
|
|
|
|
Los siguientes comandos inician el registro y descubrimiento de servicios, el orquestador de contenedores, el servidor de configuración, el servicio, un proxy del servicio que balancea la carga si hubiera diferentes instancias del servicio y admite tolerancia a fallos si alguna de las instancias falla y finalmente el cliente del servicio. En el ejemplo se utiliza Nomad y Docker junto a Consul y Traefik. El ejemplo requiere iniciar Consul y Nomad y tener instalado, configurado y en ejecución Docker.
- Microservicios con Spring Cloud, Consul, Nomad y Traefik
- Registro y descubrimiento de servicios con Spring Cloud y Consul
- Guía sobre Docker
|
|
Nomad se encarga de orquestar los contenedores de Docker para crear las instancias de los microservicios. Las definiciones de los microservicios se envian a Nomad para que inicie las instancias.
|
|
Sleuth exporta los datos de las transacciones a Zipkin donde se observa los tiempos de respuesta de los microservicios para una petición determinada dado su identificador global. Pero también permite observar que microservicios han sido llamados lo que ayuda a conocer cual ha sido el comportamiento del sistema, dependiendo de la lógica de negocio que implementen no tienen por que ser siempre los mismos.
Zipkin ofrece una aplicación web con la que consultar las llamadas desencadenadas por una petición y los tiempos de respuesta de los servicios involucrados, la aplicación web está en la dirección http://localhost:9411/zipkin/ o a través de Traefik con http://localhost:8093/zipkin/. Utilizando uno de los identificadores globales de petición e introduciéndolo en el cuadro de búsqueda de Zipkin se observan los tiempos de respuesta de cada uno de los servicios.
|
|
Tanto el microservicio cliente como el microservicio servidor tienen Sleuth integrado y envían de forma asíncrona cuando terminan las peticiones HTTP la información de trazabilidad a Zipkin. Con el traceId de una transacción se observa en Zipkin la cadena de llamadas entre los microservicios y sus tiempos de respuesta. En el ejemplo solo hay dos pero podrían en un caso real quizá sean tres, cuatro o más ya sea porque cada servicio utiliza otro o porque un mismo servicio utiliza varios, ver esta información de forma gráfica es mucho más fácil de analizar que solo con las trazas correlacionadas en ELK.
Este es el código del cliente que hace la petición al servidor y el código del servidor. Spring ya proporciona integración con Sleuth en sus utilidades como RestTemplate. Si se utiliza el cliente HTTP de Java añadido junto con otras novedades de Java 11 hay que añadir el soporte para que en la petición se añadan las cabeceras cuando se haga la petición. La forma que tiene Sleuth de compartir los identificativos de las transacciones entre el cliente y el servidor es a través de las cabeceras en las peticiones HTTP.
|
|
|
|
|
|
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 siguiente comando:./run.sh