viernes, 11 de marzo de 2022

Integrar Red Hat Fuse (Apache Camel) con OpenTracing y Jaeger

 


Apache Camel ha adoptado la iniciativa OpenTracing como framework de integración. Tiene mucho sentido usar OpenTracing debido a que se integra con multitud de lenguajes y tecnologías permitiendo que entre todos ellos compartan un framework de rastreo en común y neutro.

Habilitar el rastreo para una aplicación única y aislada no es tan útil, pero por pura simplicidad, vamos a construir un servicio instrumentado básico, muy fino y ficticio para ilustrar el procedimiento.

Conceptos

Primero debemos entender ciertos conceptos, por ejemplo:

¿Qué es OpenTracing?

OpenTracing es un estándar abierto y neutro para el tracing distribuido.

En la actualidad con el paso de los sistemas monolíticos a las arquitecturas de microservicios un sistema en producción está compuesto de un buen número de servicios, lo que hace que tareas que antes eran sencillas como análisis de errores en backend se complican.

Por suerte existen un buen número de sistemas de tracing distribuido como Zipkin, Dapper, HTrace, etc. Qué resuelven esto, aunque cada una usa su propia API. OpenTracing ofrece un API consistente y expresiva para que los desarrolladores puedan añadir trazas (o cambiar la implementación) a través de configuración.

Además OpenTracing ofrece librerías para 8 lenguajes diferentes como: Go, JavaScript, Java, Python, Ruby, Objective-C, C++, C#

¿Qué es Jaeger?

Jaeger es una plataforma open source que sirve para detectar trazas entre servicios distribuidos. Se utiliza para supervisar entornos complejos de microservicios y solucionar los problemas asociados a ellos. En resumen, una consola web para visualizar las trazas.


Introducción

El servicio ficticio que vamos a construir, simplemente expone REST, y ejecuta una instrucción de log cuando llega una solicitud. Generando automáticamente la información de rastreo y enviándola a una consola de rastreo.

Hay varias formas de activar el tracing en Apache Camel, pero vamos a hacerlo simple y utilizando el agente de Jaeger. Éste agente, para la aplicación en Apache Camel, no es más que otra dependencia de Maven, pero Jaeger interactuará con la API de OpenTracing para recoger y manipular la información generada por el propio Apache Camel.

Nuestro proyecto será armado de la siguiente manera:


Para lograr lo que se ve en la figura anterior, seguir en orden los siguientes pasos:

Prerequisitos
  • Java 1.8
  • Maven 3.6 o superior
  • Docker o Podman
1- Configurar repositorios de Maven, para ello buscamos el archivo settings.xml. Que lo encontraremos en:
  • Linux y Mac OS X: ~/.m2/repository
  • Windows: C:\Users\{your-username}\.m2\repository
Lo abrimos con algún editor, y agregamos el siguiente contenido en el lugar indicado por las etiquetas padres:

...
<profiles>
    ...
    <profile>
      <id>extra-repos</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <repositories>
       <repository>
            <id>redhat-ga-repository</id>
            <url>https://maven.repository.redhat.com/ga</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>redhat-ea-repository</id>
            <url>https://maven.repository.redhat.com/earlyaccess/all</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
          <id>jboss-public</id>
          <name>JBoss Public Repository Group</name>
          <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
            <id>redhat-ga-repository</id>
            <url>https://maven.repository.redhat.com/ga</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-ea-repository</id>
            <url>https://maven.repository.redhat.com/earlyaccess/all</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
          <id>jboss-public</id>
          <name>JBoss Public Repository Group</name>
          <url>https://repository.jboss.org/nexus/content/groups/public</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
    ...
</profiles>

Guardamos los cambios y cerramos el editor.

2- Creamos la estructura base del proyecto Fuse utilizando el arquetipo de Maven:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate \
-DarchetypeCatalog=https://maven.repository.redhat.com/ga/io/fabric8/archetypes/archetypes-catalog/2.2.0.fuse-sb2-780040-redhat-00002/archetypes-catalog-2.2.0.fuse-sb2-780040-redhat-00002-archetype-catalog.xml \
-DarchetypeGroupId=org.jboss.fuse.fis.archetypes \
-DarchetypeArtifactId=spring-boot-camel-xml-archetype \
-DarchetypeVersion=2.2.0.fuse-sb2-780040-redhat-00002

Se le pedirá que introduzca información adicional, como por ejemplo: nombre del grupo, nombre del artefacto, su version, etc. Complete esos datos:


3- Abrimos el proyecto con nuestro IDE favorito, y agregamos las dependencias maven necesarias:


Prestar atención a la dependencia de Camel Servlet y las dependencias extras necesarias para el correcto funcionamiento de OpenTracing.

4- Agregamos la anotación de OpenTracing a nuestro Application.java de la siguiente manera:



5- Agregar variables de entorno para cliente de Jaeger. En un futuro, si deseamos desplegar este proyecto en un cluster de OpenShift, el POD necesitará de algunas variables de entorno para entender y conocer cómo comunicar las trazas al cliente de Jaeger.

Abrimos el archivo src/main/fabric8/deployment.yml y agregamos las siguientes variables de entorno:


Atención: asegúrese de que la indentación en su archivo YAML sea la correcta.

El parámetro "JAEGER_SERVICE_NAME" es el nombre con el que se identifica el servicio dentro de Jaeger, "JAEGER_ENDPOINT" es la URL donde se ejecuta el recopilador y "JAEGER_SAMPLER_PARAM" establece la tasa de muestreo en 1,0 (100%), lo que indica que Jaeger registrará y rastreará cada solicitud que llegue al servicio.

6- Agregar ruta de ejemplo para probar el servicio, para ello abrimos el archivo scr/main/resources/spring/camel-context.xml y entre las etiquetas <camelContext>...</camelContext> agregamos el siguiente contenido para definir una ruta de ejemplo:

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">

  <rest>
    <get uri="/demo/{client-id}">
      <to uri="direct:main"/>
    </get>
  </rest>

  <route id="main">
    <from uri="direct:main"/>
    <log message="got request from client: ${header.client-id}"/>
  </route>

</camelContext>

El código anterior define una operación GET en una API REST con un parámetro de entrada 'client-id'. La implementación invoca una ruta principal, que simplemente registra (o logea) ese 'client-id' que se ha enviado.

7- Probemos el funcionamiento del servicio, para comprobar que la aplicación funciona como se espera. Ejecutemos localmente la aplicación con el siguiente comando de maven:

mvn spring-boot:run -DJAEGER_SERVICE_NAME=demo

Nota: observe cómo cuando ejecutamos localmente el servicio establecemos explícitamente el nombre del servicio de Jaeger como un parámetro. Si no lo hacemos, el proyecto java registraría una advertencia (Stack Trace) en el momento del arranque.

Cuando la aplicación haya iniciado completamente, ejecute el siguiente comando curl para enviar una petición que incluya el ID del cliente en su URL:

curl http://localhost:8080/camel/demo/mi-usuario

Debería ver en la salida de la aplicación (en los logs) el ID mostrando el nombre del cliente que se le envió:




Visualización de Trazas

Para visualizar las trazas en una instancia de Jaeger, lo que haremos será levantar una instancia con Docker utilizando la imagen oficial de jaeger. Y le indicaremos a nuestro servicio donde esta esa instancia a la hora de iniciarlo con maven.

1- Iniciar instancia de jaeger, para ello desde una terminal ejecutamos el siguiente comando:

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 14250:14250 -p 9411:9411 jaegertracing/all-in-one:latest

2- Ejecutar nuestro servicio usando maven, necesitaremos pasarle ciertos parámetros. Para ello, desde una terminal ejecutamos el siguiente comando:

mvn clean spring-boot:run  -DJAEGER_SERVICE_NAME=demo -DJAEGER_AGENT_HOST=localhost -DJAEGER_SAMPLER_PARAM=1

3- Consumimos el servicio demo, con el fin de que ejecute y reciba una solicitud para que registre (log) una petición y jaeger pueda tomar la información necesaria para almacenarla en su plataforma. Podemos ejecutar el mismo comando curl de antes:

curl http://localhost:8080/camel/demo/mi-usuario

4- Abrimos la consola web de Jaeger en un navegador web como Google Chrome o Firefox accediendo a la siguiente URL: http://localhost:16686/search

Buscamos el servicio "demo" en el panel de la izquierda y hacemos clic sobre "Find Traces" para buscar todas las trazas de ese servicio:


Con esta herramienta podemos ir haciendo clic en cada petición e ir viendo en detalles cada una de las llamadas a otros servicios que realizó durante su ejecución o trayectoria:

Nos permitirá en un entorno productivo debuggear con mayor exactitud y mas especificamente donde se están produciendo los errores o cuellos de botella en nuestra arquitectura de microservicios.


Recomendaciones

Si queremos desplegar este mismo servicio en un cluster de OpenShift, podemos aprovechar el plugin de fabric8 (ya incluido en el arquetipo que hemos usado).

Solamente debemos iniciar sesión en el cluster OpenShift con la utilidad de linea de comandos OC, posicionarnos en el proyecto donde queremos desplegar el servicio y ejecutar el siguiente comando maven desde una terminal:

mvn fabric8:deploy -Popenshift


También les dejo el código fuente de la aplicación de ejemplo "demo" desarrollada en este articulo por si desean mirarla en detalles:


Cualquier comentario, duda o sugerencia puede hacerse libremente y con respeto en la caja de comentarios de este articulo. 

No hay comentarios:

Publicar un comentario