La trazabilidad es uno de los mayores problemas que surgen en un sistema de microservicios. Saber que nodo de nuestra red y en que momento ha fallado es esencial para corregir errores y hacerlo rápidamente. Para hacer frente a éste problema y crear un estándar varias empresas y desarrolladores de la comunidad crearon Open Tracing.

¿Que es Open Tracing?

OpenTracing es una organización que intenta establecer un estándar sobre como llevar a cabo dicha trazabilidad.
OpenTracing nos provee de un marco de trabajo, una API y librerías para conseguir cumplir con su especificación.

Conceptos principales de Open Tracing

SPAN
El concepto fundamental sobre el que gira la especificación OpenTracing es el de “Span”.
Un Span, es la unidad básica de información que representa una acción. Por poner algunos ejemplos, una llamada de un microservicio a otro, o ejecutar una consulta una base de datos.
Ésta unidad de información se conforma de:
– Nombre de la operación
– Una marca de tiempo de inicio y otra de fin
– Tags
– Logs
– Contexto del Span

TRACERS
Los Span, son gestionados por la interfaz “Tracer”. Tracer se encarga de crear los Span, de su serialización y deserialización y de entender el contexto para poder tener trazabilidad.
Existen múltiples implementaciones de tracers para muchos lenguajes, en éste post hablaremos de Jaeger.

¿Que es Jaeger?

Jaeger es una implementación de OpenTracing desarrollada por ingenieros de Uber que no estaban conformes con el funcionamiento de Zipkin, el software mas utilizado anteriormente y con el que Jaeger es compatible.

Ejemplo

Voy a monitorizar la actividad de un sistema conformado por:
– Servicio que hará la función de frontend
– Microservicio con información de hoteles.

Arquitectura del ejemplo

Mostramos de manera gráfica como quedará nuestro sistema para probar Jaeger.
Diagrama creado con: https://cloudcraft.co/

Instalación de Jaeger en local

Jaeger en si mismo está conformado por un conjunto de servicios que recibirán la información (Spans) de los clientes que integremos. Además, nos provee de la interfaz gráfica Jaeger UI a través de la cual podremos monitorizar nuestro sistema.

Disponemos de Jaeger en un único ejecutable, o podemos descargar y compilar el código Go del projecto.
Por comodidad para éste ejemplo voy a utilizar una imagen docker en la que nos proporcionan todo un sistema Jaeger preparado para funcionar. Tras contar con la imagen docker en nuestro sistema, pondremos en marcha el servicio ejecutando:

$ docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.13

Una vez arrancado el servicio, abrimos un navegador y vamos a http://localhost:16686/ para acceder a la interfaz gráfica de Jaeger.

Dependencias

Jaeger, proporciona una librería cliente en la que podemos implementar a mano nuestros Tracers y Spans. En lugar de utilizar el cliente oficial de Jaeger, utilizaremos las implementaciones Spring Boot Starter de opentracing que está creando la comunidad.
Necesitaremos principalmente 2:
opentracing-spring-jaeger-web
opentracing-spring-web-starter

En este ejemplo, puesto que estamos utilizando la version 2 de Spring Boot, utilizaré las últimas versiones de cada librería.

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-spring-jaeger-web-starter</artifactId>
    <version>LATEST</version>
</dependency>

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-spring-web-starter</artifactId> 
    <version>LATEST</version>
</dependency>

Configuración

Añadiremos un método que nos devuelva un @Bean Tracer en nuestra clase principal de la aplicación.

@Bean
public Tracer getTracer() {
    Configuration.SamplerConfiguration samplerConfig = 
        new Configuration.SamplerConfiguration();
    Configuration.ReporterConfiguration reporterConfig = 
        new Configuration.ReporterConfiguration();

    Configuration config = new Configuration("opentracing-tutorial");
        config.withSampler(samplerConfig);
        config.withReporter(reporterConfig);

    return config.getTracer();
}

Y un RestTemplate @Bean configurado para obtener sus trazas.

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setInterceptors(Collections.singletonList(new 
    TracingRestTemplateInterceptor(tracer)));

    return restTemplate;
}

Resultados

Tras hacer varias peticiones a nuestro servicio Frontend, podemos ver accediendo a la interfaz gráfica de Jaeger las trazas que va generando nuestra aplicación.
En la pantalla principal podremos realizar una búsqueda filtrando por servicio, trazas y spans.

Si pulsamos sobre una traza, JaegerUI nos mostrará con mas detalle las llamadas de un servicio a otro.

Conclusión

A pesar de que OpenTracing no es aún un estándar y de tener una integración con Spring Boot en una fase aún temprana, ya podemos contar con trazabilidad de nuestras aplicaciones Spring y las ventajas que nos aporta.
La documentación es cambiante y los creadores avisan de que puede variar en cualquier momento y sin previo aviso, por lo que habría que estar pendiente de las novedades.
Podéis encontrar el código de ejemplo aquí.

Deja un comentario

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