BLOG | NGINX

NGINX Tutorial: How to Use OpenTelemetry Tracing to Understand Your Microservices (Tutorial de NGINX: Cómo usar OpenTelemetry las trazas para entender los microservicios)

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Javier Evans
Javier Evans
Publicado el 28 de marzo de 2023

Esta publicación es uno de los cuatro tutoriales que te ayudan a poner en práctica los conceptos de Microservicios de marzo de 2023: Comience a entregar microservicios :

 

Una arquitectura de microservicios ofrece muchos beneficios, entre ellos una mayor autonomía del equipo y una mayor flexibilidad en el escalamiento y la implementación. En el lado negativo, cuanto más servicios haya en un sistema (y una aplicación de microservicios puede tener docenas o incluso cientos), más difícil resulta mantener una imagen clara del funcionamiento general del sistema. Como escritores y mantenedores de sistemas de software complejos, sabemos la importancia vital de tener esa imagen clara. Observabilidad Las herramientas nos brindan el poder de construir esa imagen a través de numerosos servicios e infraestructura de soporte.

En este tutorial, destacamos un tipo de observabilidad muy importante para las aplicaciones de microservicios: el seguimiento. Antes de comenzar, definamos algunos términos que se utilizan comúnmente cuando hablamos de observabilidad:

  • Observabilidad : la capacidad de comprender el estado o la condición interna de un sistema complejo (como una aplicación de microservicios) basándose únicamente en el conocimiento de sus resultados externos (como seguimientos, registros y métricas).
  • Monitoreo – La capacidad de observar y verificar el progreso o estado de un objeto durante un período de tiempo. Por ejemplo, puedes monitorear el tráfico que llega a tu aplicación durante las horas pico y usar esa información para escalarla adecuadamente en respuesta.
  • Telemetría : el acto de recopilar métricas, seguimientos y registros y transferirlos desde su punto de origen a otro sistema para su almacenamiento y análisis. Además, los datos en sí.
  • Rastreo/rastreos : un relato del recorrido de una solicitud o una acción a medida que se mueve a través de todos los nodos de un sistema distribuido.
  • Intervalo : Un registro dentro de un seguimiento de una operación y sus metadatos asociados. Los rastros se componen de muchos tramos anidados.
  • Registro/registros de eventos : un registro de texto con marca de tiempo y metadatos.
  • Métrica : una medida capturada en tiempo de ejecución. Por ejemplo, la cantidad de memoria que utiliza una aplicação en un momento determinado.

Podemos utilizar todos estos conceptos para obtener información sobre el rendimiento de nuestros microservicios. El rastreo es una parte particularmente útil de una estrategia de observabilidad porque ofrece un “panorama general” de lo que sucede en múltiples componentes, a menudo acoplados de forma flexible, cuando se realiza una solicitud. También es una forma especialmente eficaz de identificar cuellos de botella en el rendimiento.

Este tutorial utiliza el kit de herramientas de rastreo de OpenTelemetry (OTel), un estándar de código abierto e independiente del proveedor para recopilar, procesar y exportar telemetría que está ganando popularidad rápidamente. En la concepción de OTel, un seguimiento divide un flujo de datos, que puede involucrar múltiples servicios, en una serie de "fragmentos" ordenados cronológicamente que pueden ayudarle a comprender fácilmente:

  • Todos los pasos que ocurrieron en un “fragmento”
  • ¿Cuánto tiempo tomaron todos estos pasos?
  • Metadatos sobre cada paso.

Si no está familiarizado con OTel, consulte ¿Qué es OpenTelemetry? para obtener una introducción detallada al estándar y consideraciones para su implementación.

Descripción general del tutorial

Este tutorial se centra en el seguimiento de las operaciones de una aplicación de microservicios con OTel. En los cuatro desafíos de este tutorial, aprenderá a rastrear una solicitud a través de su sistema y a responder preguntas sobre sus microservicios:

Estos desafíos ilustran nuestro proceso recomendado al configurar el rastreo por primera vez. Los pasos son:

  1. Comprenda el sistema así como la operación particular que está instrumentando.
  2. Decide qué necesitas saber del sistema en ejecución.
  3. Instrumente el sistema de manera “ingenua” (es decir, utilice una configuración predeterminada sin intentar eliminar información que no necesita ni recopilar puntos de datos personalizados) y evalúe si la instrumentación lo ayuda a responder sus preguntas.
  4. Modifique la información que se informa para permitirle responder esas preguntas más rápidamente.

Nota:  Nuestra intención en este tutorial es ilustrar algunos conceptos básicos sobre la telemetría, no mostrar la forma correcta de implementar microservicios en producción. Si bien utiliza una arquitectura de “microservicios” real, hay algunas advertencias importantes:

  • El tutorial no utiliza un marco de orquestación de contenedores como Kubernetes o Nomad. Esto es para que puedas aprender sobre los conceptos de microservicios sin empantanarte en los detalles de un determinado marco. Los patrones presentados aquí son portables a un sistema que ejecuta uno de estos marcos.
  • Los servicios están optimizados para facilitar la comprensión en lugar del rigor de la ingeniería de software. Lo importante es analizar el papel de un servicio en el sistema y sus patrones de comunicación, no los detalles del código. Para obtener más información, consulte los archivos README de los servicios individuales.

Arquitectura del tutorial y objetivos de telemetría

Arquitectura y flujo de usuario

Este diagrama ilustra la arquitectura general y el flujo de datos entre los microservicios y otros elementos utilizados en el tutorial.

Diagrama que muestra la topología utilizada en el tutorial, con seguimiento de OpenTelemetry de un sistema de mensajería con dos microservicios, NGINX y RabbitMQ

Los dos microservicios son:

Las tres piezas de infraestructura de apoyo son:

  • NGINX de código abierto : un punto de entrada al servicio de mensajería y al sistema en general
  • RabbitMQ : un popular agente de mensajes de código abierto que permite que los servicios se comuniquen de forma asincrónica
  • Jaeger : un sistema de rastreo distribuido de extremo a extremo de código abierto para recopilar y visualizar la telemetría de los componentes del sistema que la producen.

Dejando a OTel de lado por un momento, podemos concentrarnos en la secuencia de eventos que estamos rastreando: qué sucede cuando un usuario envía un nuevo mensaje de chat y el destinatario es notificado al respecto.

Diagrama que muestra el flujo de información en el sistema de mensajería utilizado en el tutorial

El flujo se descompone así:

  1. Un usuario envía un mensaje al servicio de mensajería . El proxy inverso NGINX intercepta el mensaje y lo reenvía a una de las muchas instancias del servicio de mensajería .
  2. El servicio de mensajería escribe el nuevo mensaje en su base de datos.
  3. El servicio de mensajería produce un evento en una cola de mensajes de RabbitMQ llamado chat_queue para indicar que se envió un mensaje. El evento es genérico y no tiene un objetivo específico.
  4. Al mismo tiempo:

    • 4a. El servicio de mensajería devuelve una respuesta al remitente informando que el mensaje se envió correctamente.
    • 4b. El servicio notificador detecta el nuevo evento en chat_queue y lo consume.
  5. El servicio notificador verifica en su base de datos las preferencias de notificación del destinatario del nuevo mensaje.
  6. El servicio de notificación utiliza el método preferido del destinatario para enviar una o varias notificaciones (en este tutorial, las opciones de método son SMS y correo electrónico).

Objetivos de telemetría

Al configurar la instrumentación de telemetría, es mejor comenzar con un conjunto de objetivos para la instrumentación más definidos que "enviar todo y esperar obtener información". Tenemos tres objetivos clave de telemetría para este tutorial:

  1. Comprenda todos los pasos por los que pasa una solicitud durante el flujo de un nuevo mensaje
  2. Tenga confianza en que el flujo se ejecuta de extremo a extremo en cinco segundos en condiciones normales.
  3. Vea cuánto tiempo tarda el servicio notificador en comenzar a procesar el evento enviado por el servicio de mensajería (una demora excesiva podría significar que el servicio notificador tiene problemas para leer la cola de eventos y los eventos se están acumulando)

Tenga en cuenta que estos objetivos están relacionados tanto con el funcionamiento técnico del sistema como con la experiencia del usuario.

Requisitos previos y configuración del tutorial

Requisitos previos

Para completar el tutorial en su propio entorno, necesitará:

  • Un entorno compatible con Linux/Unix

    Nota:  Las actividades de este tutorial que implican el seguimiento de NGINX no funcionan en procesadores basados en ARM porque el módulo OpenTelemetry para NGINX no es compatible. (Esto incluye arquitecturas Linux aarch64 y máquinas Apple con el chip M1 o M2). Las actividades que involucran los servicios de mensajería y notificación funcionan en todas las arquitecturas.

  • Conocimiento básico de la línea de comandos de Linux, JavaScript y bash (pero se proporcionan y explican todos los códigos y comandos, por lo que aún puede tener éxito con un conocimiento limitado)
  • Docker y Docker Compose
  • Node.js 19.x o posterior

    • Probamos la versión 19.x, pero esperamos que las versiones más nuevas de Node.js también funcionen.
    • Para obtener información detallada sobre la instalación de Node.js, consulte el archivo README en el repositorio del servicio de mensajería . También puedes instalar asdf para obtener exactamente la misma versión de Node.js utilizada en el tutorial.
  • curl (ya instalado en la mayoría de los sistemas)
  • Las tecnologías enumeradas en Arquitectura y flujo de usuario : mensajero y notificador (los descargará en la siguiente sección), NGINX de código abierto , Jaeger y RabbitMQ .

Nota:  El tutorial utiliza el SDK de JavaScript porque los servicios de mensajería y notificación están escritos en Node.js. También puede configurar la función de instrumentación automática de OTel (también llamada autoinstrumentación ) para tener una idea del tipo de información disponible de OTel. El tutorial explica todo lo que necesita saber sobre el SDK Node.js de OTel, pero para obtener más detalles, consulte la documentación de OTel .

Configuración

  1. Iniciar una sesión de terminal.
  2. En su directorio de inicio, cree el directorio microservices-march y clone en él los repositorios de GitHub para este tutorial. (También puede utilizar un nombre de directorio diferente y adaptar las instrucciones en consecuencia).

    Nota:  A lo largo del tutorial se omite el aviso en la línea de comandos de Linux para que sea más fácil copiar y pegar los comandos en su terminal. La tilde ( ~ ) representa su directorio de inicio.

    mkdir ~/microservices-marchcd ~/microservices-march
    Clon de git https://github.com/microservices-march/messenger --branch mm23-metrics-start
    Clon de git https://github.com/microservices-march/notifier --branch mm23-metrics-start
    Clon de git https://github.com/microservices-march/platform --branch mm23-metrics-start
    

Desafío 1: Configurar la instrumentación básica de OTel

En este desafío , inicia el servicio de mensajería y configura la instrumentación automática de OTel para enviar telemetría a la consola.

Lanzar el servicio de mensajería

  1. Cambie al repositorio de la plataforma e inicie Docker Compose:

    cd ~/microservices-march/platformdocker componer -d --build
    

    Esto inicia RabbitMQ y Jaeger, que se utilizarán en desafíos posteriores.

    • La bandera -d le indica a Docker Compose que se separe de los contenedores cuando se hayan iniciado (de lo contrario, los contenedores permanecerán conectados a su terminal).
    • El indicador --build le indica a Docker Compose que reconstruya todas las imágenes al iniciarse. Esto garantiza que las imágenes que está ejecutando se mantengan actualizadas ante cualquier posible cambio en los archivos.
  2. Cambie al directorio de la aplicación en el repositorio de Messenger e instale Node.js (puede sustituir un método diferente si lo desea):

    cd ~/microservices-march/messenger/appasdf install
    
  3. Instalar dependencias:

    instalación de npm
    
  4. Inicie la base de datos PostgreSQL para el servicio de mensajería :

    docker componer -d
    
  5. Cree el esquema y las tablas de la base de datos e inserte algunos datos semilla:

    npm ejecuta refresh-db
    

Configurar la instrumentación automática de OTel enviada a la consola

Con la instrumentación automática de OTel, no es necesario modificar nada en el código base del mensajero para configurar el seguimiento. En lugar de importarse al código de la aplicação , toda la configuración de seguimiento se define en un script que se importa al proceso Node.js en tiempo de ejecución.

Aquí se configura la instrumentación automática del servicio de mensajería con el destino más básico para los seguimientos: la consola. En el desafío 2 , cambiarás la configuración para enviar rastros a Jaeger como un recopilador externo.

  1. Aún trabajando en el directorio de aplicaciones del repositorio de mensajería , instale los paquetes principales de OTel Node.js:

    npm install @opentelemetry/sdk-node@0.36.0 \
    @opentelemetry/auto-instrumentations-node@0.36.4
    

    Estas bibliotecas proporcionan la siguiente funcionalidad:

    • @opentelemetry/sdk-node – Generación y exportación de datos OTel
    • @opentelemetry/auto-instrumentations-node – Configuración automática con configuración predeterminada de todas las instrumentaciones Node.js más comunes

    Nota:  Una peculiaridad de OTel es que sus SDK de JavaScript están divididos en fragmentos muy, muy pequeños. Instalarás algunos paquetes más solo para el ejemplo básico de este tutorial. Para comprender qué paquetes podría necesitar para realizar tareas de instrumentación más allá de las cubiertas en este tutorial, consulte las (muy buenas) guías de inicio de OTel y consulte el repositorio de GitHub de OTel.

  2. Cree un nuevo archivo llamado tracing.mjs para contener el código de configuración e instalación para el rastreo de OTel:

    rastreo táctil.mjs
    
  3. En su editor de texto preferido, abra tracing.mjs y agregue este código:

    //1
    Importar OpenTelemetry desde "@opentelemetry/sdk-node";
    Importar { getNodeAutoInstrumentations } desde "@opentelemetry/auto-instrumentations-node";
    
    //2
    Const SDK = new OpenTelemetry.NodeSDK({
    traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
    Instruments: [getNodeAutoInstrumentations()],
    });
    
    //3
    Sdk.start();
    

    El código hace lo siguiente:

    1. Importa las funciones y los objetos necesarios del SDK de OTel.
    2. Crea una nueva instancia de NodeSDK y la configura para:

      • Envía intervalos a la consola ( ConsoleSpanExporter ).
      • Utilice el autoinstrumentador como conjunto base de instrumentación. Esta instrumentación carga todas las bibliotecas de autoinstrumentación más comunes. En el tutorial los relevantes son:

        • @opentelemetry/instrumentation-pg para la biblioteca de base de datos Postgres ( pg )
        • @opentelemetry/instrumentation-express para el marco Node.js Express
        • @opentelemetry/instrumentation-amqplib para la biblioteca RabbitMQ ( amqplib )
    3. Inicia el SDK.
  4. Inicie el servicio de mensajería e importe el script de instrumentación automática que creó en el paso 3.

    nodo --import ./tracing.mjs index.mjs
    

    Después de un momento, comienzan a aparecer en la consola (su terminal) muchos resultados relacionados con el seguimiento:

    ...
    {
    Identificador de seguimiento: '9c1801593a9d3b773e5cbd314a8ea89c',
    parentId: indefinido,
    traceState: indefinido,
    name: 'fs statSync',
    id: '2ddf082c1d609fbe', tipo: 0,
    marca de tiempo: 1676076410782000, duración: 3,
    atributos: {},
    estado: { código: 0},
    eventos: [],
    enlaces: []
    }
    ...
    

Nota:  Deje la sesión de terminal abierta para su reutilización en el desafío 2.

Desafío 2: Configurar la instrumentación OTel y la visualización de trazas para todos los servicios

Hay muchas herramientas que puedes usar para ver y analizar rastros, pero este tutorial usa Jaeger . Jaeger es un marco de seguimiento distribuido de extremo a extremo , simple y de código abierto, con una interfaz de usuario basada en web incorporada para visualizar intervalos y otros datos de seguimiento. La infraestructura proporcionada en el repositorio de la plataforma incluye Jaeger (lo inició en el Paso 1 del Desafío 1), por lo que puede concentrarse en analizar datos en lugar de lidiar con herramientas complejas.

Se puede acceder a Jaeger en el punto final http://localhost:16686 de su navegador, pero si accede al punto final ahora mismo, no hay nada que ver sobre su sistema. ¡Esto se debe a que los rastros que estás recopilando actualmente se están enviando a la consola! Para ver datos de seguimiento en Jaeger, debe exportar los seguimientos utilizando el formato del protocolo OpenTelemetry (OTLP).

En este desafío, instrumentas el flujo de usuario principal configurando la instrumentación para:

Configurar la instrumentación automática de OTel enviada a un recopilador externo

Como recordatorio, el uso de la instrumentación automática de OTel significa que no es necesario modificar nada en el código base del mensajero para configurar el seguimiento. En cambio, toda la configuración de seguimiento se encuentra en un script que se importa al proceso Node.js en tiempo de ejecución. Aquí cambia el destino de los rastros generados por el servicio de mensajería desde la consola a un recopilador externo (Jaeger en este tutorial).

  1. Siguiendo trabajando en la misma terminal que en el Desafío 1, y en el directorio de la aplicación del repositorio de messenger , instala el paquete Node.js del exportador OTLP:

    npm install @opentelemetry/exporter-trace-otlp-http@0.36.0
    

    La biblioteca @opentelemetry/exporter-trace-otlp-http exporta información de seguimiento en formato OTLP a través de HTTP. Se utiliza cuando se envía telemetría a un colector externo OTel.

  2. Abra tracing.mjs (que creó y editó en el Desafío 1) y realice estos cambios:

    • Agregue esta línea al conjunto de declaraciones de importación en la parte superior del archivo:

      importar { OTLPTraceExporter } desde "@opentelemetry/exporter-trace-otlp-http";
      
    • Cambie el “exportador” que proporciona al SDK de OTel del exportador de consola utilizado en el Desafío 1 a uno que pueda enviar datos OTLP a través de HTTP a un recopilador compatible con OTLP. Reemplazar:

      traceExporter: nuevo opentelemetry.tracing.ConsoleSpanExporter(),
      

      con:

      traceExporter: nuevo OTLPTraceExporter({ encabezados: {} }),
      

    Nota:  Para simplificar, el tutorial asume que el recopilador se encuentra en la ubicación predeterminada, http://localhost:4318/v1/traces . En un sistema real, es una buena idea establecer la ubicación explícitamente.

  3. Presione Ctrl+c para detener el servicio de mensajería que inició en esta terminal en el Paso 4 de Configurar la instrumentación automática de OTel enviada a la consola . Luego reinícielo para utilizar el nuevo exportador configurado en el Paso 2:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Inicie una segunda sesión de terminal independiente. (Las instrucciones siguientes denominan a esto terminal del cliente y al terminal original, utilizado en los pasos 1 y 3, terminal de mensajería ). Espere unos diez segundos y luego envíe una solicitud de verificación de estado al servicio de mensajería (puede ejecutar esto varias veces si desea ver varios seguimientos):

    curl -X GET http://localhost:4000/salud
    

    Esperar diez segundos antes de enviar la solicitud ayuda a que su seguimiento sea más fácil de encontrar, porque viene después de los muchos seguimientos que la instrumentación automática genera a medida que se inicia el servicio.

  5. En un navegador, acceda a la interfaz de usuario de Jaeger en http://localhost:16686 y verifique que el exportador OTLP funcione como se espera. Haga clic en Buscar en la barra de título y en el menú desplegable del campo Servicio seleccione el servicio cuyo nombre comienza con unknown_service . Haga clic en el botón Buscar rastros :

  6. Haga clic en un trazo en el lado derecho de la ventana para mostrar una lista de los intervalos que contiene. Cada intervalo describe las operaciones, que a veces involucran múltiples servicios, que se ejecutaron como parte del seguimiento. El intervalo jsonParser en la captura de pantalla muestra cuánto tiempo tomó ejecutar la parte jsonParser del código de manejo de solicitudes del servicio de mensajería .

    Captura de pantalla de la GUI de Jaeger que muestra la lista de intervalos para unknown_service, antes de que se cambie la instrumentación automática para mostrar los nombres de servicio correctos

  7. Como se señaló en el Paso 5, el nombre del servicio exportado por el SDK de OTel ( unknown_service ) no es significativo. Para solucionar esto, en la terminal de mensajería presione Ctrl+c para detener el servicio de mensajería . Luego instale un par de paquetes Node.js más:

    ^c
    npm install @opentelemetry/convenciones-semánticas@1.10.0 \
    @opentelemetry/recursos@1.10.0
    

    Estas dos bibliotecas proporcionan la siguiente funcionalidad:

    • @opentelemetry/semantic-conventions – Define los atributos estándar para los seguimientos según se define en la especificación OTel.
    • @opentelemetry/resources – Define un objeto (recurso) que representa la fuente que genera los datos de OTel (en este tutorial, el servicio de mensajería ).
  8. Abra tracing.mjs en un editor de texto y realice estos cambios:

    • Agregue estas líneas al conjunto de declaraciones de importación en la parte superior del archivo:

      importar { Recurso } de "@opentelemetry/recursos"; importar { Atributos de recursos semánticos } de "@opentelemetry/convenciones-semánticas";
      
    • Cree un recurso llamado messenger bajo la clave correcta en la especificación OTel agregando la siguiente línea después de la última declaración de importación :

      const recurso = nuevo Recurso({ [SemanticResourceAttributes.SERVICE_NAME]: "mensajero", });
      
    • Pase el objeto de recurso al constructor NodeSDK agregando la línea resaltada en naranja entre las líneas en negro:

      const sdk = new opentelemetry.NodeSDK({ recurso, traceExporter: new OTLPTraceExporter({ encabezados: {} }), instrumentaciones: [getNodeAutoInstrumentations()], });
      
  9. Reiniciar el servicio de mensajería :

    nodo --import ./tracing.mjs index.mjs
    
  10. Espere unos diez segundos, luego, en la terminal del cliente (que abrió en el paso 4), envíe otra solicitud de verificación de estado al servidor (puede ejecutar el comando varias veces si desea ver varios seguimientos):

    curl -X GET http://localhost:4000/salud
    

    Nota:  Deje la terminal del cliente abierta para su reutilización en la siguiente sección y la terminal de mensajería abierta para su reutilización en el Desafío 3.

  11. Confirme que aparezca un nuevo servicio llamado Messenger en la interfaz de usuario de Jaeger en el navegador (esto puede tardar unos segundos y es posible que deba actualizar la interfaz de usuario de Jaeger):

    Captura de pantalla de la GUI de Jaeger que muestra el mensajero en la lista de servicios disponibles para una inspección en profundidad de los psans

  12. Seleccione Messenger en el menú desplegable Servicio y haga clic en el botón Buscar rastros para ver todos los rastros recientes originados en el servicio de Messenger (la captura de pantalla muestra los 2 más recientes de 20):

    Captura de pantalla de la GUI de Jaeger que muestra los 2 rastros más recientes del servicio de mensajería

  13. Haga clic en un trazo para visualizar los intervalos que contiene. Cada tramo está etiquetado correctamente como originario del servicio de mensajería :

    Captura de pantalla de la GUI de Jaeger que muestra los detalles de un solo intervalo de mensajería

Configurar la autoinstrumentación del servicio notificador de OTel

Ahora inicie y configure la instrumentación automática para el servicio notificador , ejecutando básicamente los mismos comandos que en las dos secciones anteriores para el servicio de mensajería .

  1. Abra una nueva sesión de terminal (llamada terminal notificadora en los pasos siguientes). Cambie al directorio de la aplicación en el repositorio del notificador e instale Node.js (puede sustituirlo por un método diferente si lo desea):

    cd ~/microservicios-marzo/notificador/appasdf instalar
    
  2. Instalar dependencias:

    instalación de npm
    
  3. Inicie la base de datos PostgreSQL para el servicio notificador :

    docker componer -d
    
  4. Cree el esquema y las tablas de la base de datos e inserte algunos datos semilla:

    npm ejecuta refresh-db
    
  5. Instale los paquetes Node.js de OTel (para obtener una descripción de lo que hacen los paquetes, consulte los Pasos 1 y 3 en Configurar la instrumentación automática de OTel enviada a la consola ):

    npm install @opentelemetry/auto-instrumentations-node@0.36.4 \
    @opentelemetry/exporter-trace-otlp-http@0.36.0 \
    @opentelemetry/resources@1.10.0 \
    @opentelemetry/sdk-node@0.36.0 \
    @opentelemetry/semantic-conventions@1.10.0
    
  6. Crea un nuevo archivo llamado tracing.mjs :

    rastreo táctil.mjs
    
  7. En su editor de texto preferido, abra tracing.mjs y agregue el siguiente script para poner en funcionamiento el SDK de OTel:

    Importar opentelemetry desde "@opentelemetry/sdk-node";
    Importar { getNodeAutoInstrumentations } desde "@opentelemetry/auto-instrumentations-node";
    Importar { OTLPTraceExporter } desde "@opentelemetry/exporter-trace-otlp-http";
    Importar { Resource } desde "@opentelemetry/resources";
    Importar { SemanticResourceAttributes } desde "@opentelemetry/semantic-conventions";
    
    Const resource = new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: "notifier",
    });
    
    Const sdk = new opentelemetry.NodeSDK({
    resource,
    traceExporter: new OTLPTraceExporter({ headers: {} }),
    Instruments: [getNodeAutoInstrumentations()],
    });
    
    sdk.start();
    

    Nota:  Este script es exactamente el mismo que el del servicio de mensajería , excepto que el valor en el campo SemanticResourceAttributes.SERVICE_NAME es notifier .

  8. Inicie el servicio de notificación con la instrumentación automática de OTel:

    nodo --import ./tracing.mjs index.mjs
    
  9. Espere unos diez segundos y luego, en la terminal del cliente, envíe una solicitud de verificación de estado al servicio notificador . Este servicio está escuchando en el puerto 5000 para evitar conflictos con el servicio de mensajería que escucha en el puerto 4000:

    curl http://localhost:5000/salud
    

    Nota:  Deje las terminales del cliente y del notificador abiertas para su reutilización en el desafío 3.

  10. Confirme que aparezca un nuevo servicio llamado notificador en la interfaz de usuario de Jaeger en el navegador:

    Captura de pantalla de la GUI de Jaeger que muestra el notificador en la lista de servicios disponibles para la inspección en profundidad de los tramos

Configurar la instrumentación OTel de NGINX

Para NGINX, configure el seguimiento manualmente en lugar de utilizar el método de instrumentación automática de OTel. Actualmente, la forma más común de instrumentar NGINX usando OTel es usar un módulo escrito en C. Los módulos de terceros son una parte importante del ecosistema NGINX, pero requieren cierto trabajo para su configuración. Este tutorial realiza la configuración por usted. Para obtener información de fondo, consulte Compilación de módulos dinámicos de terceros para NGINX y NGINX Plus en nuestro blog.

  1. Inicie una nueva sesión de terminal (la terminal NGINX ), cambie el directorio a la raíz del repositorio de mensajería y cree un nuevo directorio llamado load-balancer , además de nuevos archivos llamados Dockerfile , nginx.conf y opentelemetry_module.conf :

    cd ~/microservices-march/messenger/mkdir balanceador de carga
    cd balanceador de carga
    tocar Dockerfile
    tocar nginx.conf
    tocar opentelemetry_module.conf
    
  2. En su editor de texto preferido, abra Dockerfile y agregue lo siguiente (los comentarios explican lo que hace cada línea, pero puede construir y ejecutar el contenedor Docker sin comprenderlo todo):

    FROM --platform=amd64 nginx:1.23.1 # Reemplace el archivo nginx.conf con el nuestro COPY nginx.conf /etc/nginx/nginx.conf # Defina la versión del módulo NGINX OTel ARG OPENTELEMETRY_CPP_VERSION=1.0.3 # Defina la ruta de búsqueda para las bibliotecas compartidas utilizadas al compilar y ejecutar NGINX ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/opentelemetry-webserver-sdk/sdk_lib/lib # 1. Descargue la última versión de la plantilla Consul y el módulo de servidor web OTel C++, otel-webserver-module AGREGAR https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/download/webserver%2Fv${OPENTELEMETRY_CPP_VERSION}/opentelemetry-webserver-sdk-x64-linux.tgz /tmp EJECUTAR apt-get update \ && apt-get install -y --no-install-recommends dumb-init unzip \ # 2. Extraiga los archivos del módulo && tar xvfz /tmp/opentelemetry-webserver-sdk-x64-linux.tgz -C /opt \ && rm -rf /tmp/opentelemetry-webserver-sdk-x64-linux.tgz \ # 3. Instale y agregue la directiva 'load_module' en la parte superior del archivo de configuración principal de NGINX && /opt/opentelemetry-webserver-sdk/install.sh \ && echo "load_module /opt/opentelemetry-webserver-sdk/WebServerModule/Nginx/1.23.1/ngx_http_opentelemetry_module.so;\n$(cat /etc/nginx/nginx.conf)" > /etc/nginx/nginx.conf # 4. Copiar en el archivo de configuración del módulo NGINX OTel COPY opentelemetry_module.conf /etc/nginx/conf.d/opentelemetry_module.conf EXPOSE 8085 STOPSIGNAL SIGQUIT
    
  3. Abra nginx.conf y agregue lo siguiente:

    eventos {}
    http {
    include /etc/nginx/conf.d/opentelemetry_module.conf;
    
    mensajero ascendente {
    servidor localhost:4000;
    }
    
    servidor {
    escuchar 8085;
    
    ubicación / {
    contraseña_proxy http://mensajero;
    }
    }
    }
    

    Este archivo de configuración NGINX extremadamente básico le dice a NGINX que:

    • Configurar un grupo ascendente llamado mensajero que represente el grupo de instancias del servicio de mensajería
    • Escuche solicitudes HTTP en el puerto 8085
    • Reenviar todas las solicitudes entrantes para rutas que comiencen con / (es decir, todas las solicitudes entrantes) al mensajero ascendente

    Nota:  Esto se acerca bastante a la configuración real de NGINX como proxy inverso y balanceador de carga en un entorno de producción. La única diferencia importante es que el argumento de la directiva del servidor en el bloque ascendente suele ser un nombre de dominio o una dirección IP en lugar de localhost .

  4. Abra opentelemetry_module.conf y agregue lo siguiente:

    NginxModuleEnabled ON;NginxModuleOtelSpanExporter otlp;
    NginxModuleOtelExporterEndpoint localhost:4317;
    NginxModuleServiceName messenger-lb;
    NginxModuleServiceNamespace MicroservicesMarchDemoArchitecture;
    NginxModuleServiceInstanceId DemoInstanceId;
    NginxModuleResolveBackends ON;
    NginxModuleTraceAsError ON;
    
  5. Cree una imagen Docker que contenga NGINX así como el módulo NGINX OTel:

    docker build -t messenger-lb .
    
  6. Inicie el contenedor Docker para el proxy inverso NGINX y el balanceador de carga:

    docker run --rm --name messenger-lb -p 8085:8085 --network="host" messenger-lb
    
  7. En la terminal del cliente, envíe una solicitud de verificación de estado al servicio de mensajería a través del proxy inverso NGINX y el balanceador de carga (no es necesario esperar antes de enviar esta solicitud):

    curl http://localhost:8085/salud
    

    Nota:  Deje las terminales NGINX y del cliente abiertas para su reutilización en el Desafío 3.

  8. En el navegador, confirme que el nuevo servicio messenger-lb aparezca en la interfaz de usuario de Jaeger junto con los servicios que inició anteriormente. Es posible que necesites volver a cargar la interfaz de usuario de Jaeger en tu navegador.

    Captura de pantalla de la GUI de Jaeger que muestra la lista de servicios disponibles para la inspección en profundidad de tramos, que ahora incluye messenger-lb

Desafío 3: Aprenda a leer los rastros de OTel

En Arquitectura y flujo de usuario , describimos las etapas del flujo de usuario, pero para recapitular:

  1. Un usuario inicia una conversación enviando un mensaje a otro usuario.
  2. El proxy inverso NGINX intercepta el mensaje y lo reenvía al servicio de mensajería .
  3. El servicio de mensajería escribe el mensaje en su base de datos y luego envía un evento a través de RabbitMQ.
  4. El servicio notificador consume ese evento, busca las preferencias de notificación del destinatario (segundo usuario) y envía una notificación al destinatario a través del método preferido.

Y los objetivos de implementar la telemetría son:

  1. Comprenda todos los pasos que sigue una solicitud para completar el nuevo flujo de mensajes.
  2. Tenga confianza en que el flujo se ejecuta de extremo a extremo en cinco segundos en condiciones normales.
  3. Vea cuánto tiempo tarda el servicio notificador en comenzar a procesar el evento enviado por el servicio de mensajería .

En este desafío aprenderás a evaluar si las trazas generadas por la instrumentación OTel satisfacen los objetivos antes mencionados. Primero, prueba el sistema y crea algunos rastros . Luego, inspecciona el seguimiento de un flujo de mensajes y las secciones del mismo generadas por NGINX , el servicio de mensajería y el servicio de notificación .

Crear datos de seguimiento

En la terminal del cliente, configure una conversación y envíe un par de mensajes entre dos usuarios:

curl -X POST \
-H "Tipo de contenido: aplicação/json" \
-d '{"identificadores_de_participantes": [1, 2]}' \
' <a href="http://localhost:8085/conversations">http://localhost:8085/conversaciones</a> '

curl -X POST \
-H "Id. de usuario: 1" \
-H "Tipo de contenido: aplicação/json" \
-d '{"contenido": "Este es el primer mensaje"}' \
'http://localhost:8085/conversations/1/messages'

curl -X POST \
-H "ID de usuario: 2" \
-H "Tipo de contenido: aplicação/json" \
-d '{"contenido": "Este es el segundo mensaje"}' \
'http://localhost:8085/conversations/1/messages'

El servicio notificador genera una salida como la siguiente y aparece en la terminal del notificador:

Nuevo mensaje recibido: {"type":"new_message","channel_id":1,"user_id":1,"index":1,"participant_ids":[1,2]} Se envía notificación de nuevo mensaje por SMS al 12027621401

Nuevo mensaje recibido: {"type":"new_message","channel_id":1,"user_id":2,"index":2,"participant_ids":[1,2]}

Se envía notificación de nuevo mensaje por correo electrónico a the_hotstepper@kamo.ze

Se envía notificación de nuevo mensaje por SMS al 19147379938

Prepárese para leer los rastros

Abra la interfaz de usuario de Jaeger en el navegador, seleccione messenger-lb en el menú desplegable Servicio y haga clic en el botón Buscar rastros . Aparece una lista de rastros, comenzando desde el principio del flujo. Haga clic en cualquier rastro para ver detalles al respecto, como en esta captura de pantalla:

Captura de pantalla de la GUI de Jaeger que muestra el conjunto completo de tramos en el flujo

Haz clic y explora un poco. Luego, antes de continuar, considere cómo la información en los trazos respalda sus objetivos de instrumentación enumerados en la introducción del Desafío 3. Las preguntas pertinentes incluyen:

  • ¿Qué información ayuda a alcanzar los objetivos?
  • ¿Qué información falta?
  • ¿Qué información no es relevante?

Examine la sección NGINX (messenger-lb) del Trace

Objetivo 1: Ver todos los pasos que sigue una solicitud en el flujo de mensajes nuevos

Comience con el span NGINX, que tiene 11 spans secundarios dentro del span principal. Dado que la configuración actual de NGINX es muy simple, los intervalos secundarios no son muy interesantes y simplemente muestran el tiempo necesario para cada paso en el ciclo de vida del procesamiento de solicitudes de NGINX. Sin embargo, el tramo padre (el primero) contiene algunas ideas interesantes:

Captura de pantalla de la GUI de Jaeger que muestra el intervalo principal en la sección NGINX (messenger-lb) del seguimiento

  • En Etiquetas verás los siguientes atributos:

    • Campo http.methodPOST (en términos REST esto significa creación)
    • Campo http.status_code201 (indicando creación exitosa)
    • Campo http.targetconversaciones/1/mensajes (el punto final del mensaje)

    En conjunto, estos tres datos se combinan para decir: “Se envió una solicitud POST a /conversations/1/messages y la respuesta fue201 (creado exitosamente)”. Esto corresponde a los pasos 1 y 4a en Arquitectura y flujo de usuario ).

  • En Proceso , el campo webengine.name muestra que esta es la parte NGINX de la solicitud.

Además, debido a que los intervalos para el mensajero y el notificador están anidados dentro del intervalo messenger-lb conversations/1 (como se muestra en la captura de pantalla en Prepárese para leer los rastros ), puede saber que la solicitud enviada al servicio de mensajero a través del proxy inverso NGINX alcanzó todos los componentes esperados en el flujo.

Esta información satisface el objetivo porque se puede ver que el proxy inverso NGINX era parte del flujo.

Objetivo 2: Verifique que el flujo se ejecute en cinco segundos

En la lista de intervalos denominados messenger-lb , observe el intervalo más reciente (está en la parte inferior de la lista) para ver cuánto tiempo tomó la parte NGINX de la solicitud. En la captura de pantalla, el lapso comenzó en 589 microsegundos (µs) y duró 24µs, lo que significa que la operación completa del proxy inverso tomó solo 613µs, aproximadamente 0,6 milisegundos (ms). (Los valores exactos, por supuesto, serán diferentes cuando ejecute el tutorial usted mismo).

Captura de pantalla de la GUI de Jaeger que muestra los intervalos en la sección NGINX (messenger-lb) del seguimiento

En una configuración como esta, en la mayoría de los casos los valores sólo son útiles en relación con otras mediciones y varían entre sistemas. En este caso, sin embargo, está claro que la operación no corre ningún peligro de llegar a durar cinco segundos.

Esta información satisface el objetivo porque se puede ver que las operaciones de NGINX no tomaron ni cerca de cinco segundos. Si hay una operación muy lenta en el flujo, debe estar ocurriendo más tarde.

Objetivo 3: Vea cuánto tiempo tarda el servicio de notificación en leer el evento enviado por el servicio de mensajería

La capa de proxy inverso de NGINX no incluye ninguna información sobre esto, por lo que puede pasar a los intervalos de mensajería .

Examinar la sección de mensajería del Trace

Objetivo 1: Ver todos los pasos que sigue una solicitud en el flujo de mensajes nuevos

La sección del servicio de mensajería del trazado contiene otros 11 tramos. Nuevamente, la mayoría de los intervalos secundarios se refieren a los pasos básicos que utiliza el marco Express al procesar una solicitud y no son muy interesantes. Sin embargo, el tramo padre (el primero) contiene nuevamente algunas ideas interesantes:

Captura de pantalla de la GUI de Jaeger que muestra el intervalo principal en la sección de mensajería del seguimiento

En Etiquetas verás los siguientes atributos:

  • Campo http.methodPOST (de nuevo, en términos REST esto significa creación)
  • Campo http.route/conversations/:conversationId/messages (la ruta del mensaje)
  • Campo http.target/conversations/1/messages (el punto final del mensaje)

Esta información satisface el objetivo porque nos muestra que el servicio de mensajería era parte del flujo y el punto final alcanzado era el nuevo punto final del mensaje.

Objetivo 2: Verifique que el flujo se ejecute en cinco segundos

Como se indica en la siguiente captura de pantalla, la parte del mensajero del seguimiento comenzó en 1,28 ms y finalizó en 36,28 ms, para un tiempo total de 35 ms. La mayor parte de ese tiempo se dedicó a analizar JSON ( middleware : jsonParser ) y, en mucha mayor medida, a conectarse a la base de datos ( pg-pool.connect y tcp.connect ).

Esto tiene sentido dado que también se realizan varias consultas SQL en el proceso de escritura del mensaje. Esto, a su vez, sugiere que es posible que desees ampliar la configuración de instrumentación automática para capturar el tiempo de esas consultas. (El tutorial no muestra esta instrumentación adicional, pero en el Desafío 4 se crean manualmente intervalos que a su vez pueden usarse para encapsular consultas de base de datos).

Captura de pantalla de la GUI de Jaeger que muestra los intervalos en la sección de mensajería del seguimiento y cuánto tiempo tomaron

Esta información satisface el objetivo porque demuestra que las operaciones del mensajero no duran ni cerca de cinco segundos. Si hay una operación muy lenta en el flujo, debe estar ocurriendo más tarde.

Objetivo 3: Vea cuánto tiempo tarda el servicio de notificación en leer el evento enviado por el servicio de mensajería

Al igual que los intervalos NGINX, los intervalos del mensajero no incluyen esta información, por lo que puede pasar a los intervalos del notificador .

Examinar la sección de notificador del Trace

Objetivo 1: Ver todos los pasos que sigue una solicitud en el flujo de mensajes nuevos

La sección de notificador del seguimiento contiene solo dos intervalos:

Captura de pantalla de la GUI de Jaeger que muestra los dos tramos en la sección de notificador del seguimiento

  • El intervalo de proceso chat_queue : confirma que el servicio notificador procesó un evento de la cola de mensajes chat_queue
  • El intervalo pg-pool.connect : muestra que después de procesar el evento, el servicio notificador realizó algún tipo de conexión a su base de datos.

La información disponible en estos tramos sólo cumple parcialmente el objetivo de comprender cada paso. Puedes ver que el servicio notificador llegó al punto de consumir el evento de la cola, pero no sabes si:

  • La notificación de mensaje enviada por este servicio corresponde al evento enviado por el servicio de mensajería.
  • Las notificaciones de mensajes relevantes se enviaron correctamente al destinatario del mensaje.

Esto indica que es necesario hacer lo siguiente para comprender completamente el flujo del servicio de notificación :

  • Instrumentar manualmente los intervalos que muestran el envío de una notificación
  • Asegúrese de que exista una conexión explícita entre el evento enviado por el servicio de mensajería y el evento consumido por el servicio de notificación , en forma de un ID de seguimiento.

Objetivo 2: Verifique que el flujo se ejecute en cinco segundos

Si observamos el tiempo general de los intervalos del servicio de notificación , veremos que la solicitud pasó 30,77 ms en la sección de notificación del flujo. Sin embargo, debido a que no hay intervalos que señalen el “final” de todo el flujo (el envío de notificaciones al destinatario), no se puede determinar el tiempo total de esta sección del flujo ni el tiempo de finalización general de la operación.

Objetivo 3: Vea cuánto tiempo tarda el servicio de notificación en leer el evento enviado por el servicio de mensajería

Sin embargo, puedes ver que un lapso de proceso de chat_queue para el servicio de notificación comenzó a los 6,12 ms, 2 ms después de que un lapso de envío de chat_queue comenzara para el servicio de mensajería a los 4,12 ms.

Captura de pantalla de la GUI de Jaeger que muestra el servicio de notificación consumiendo un evento enviado por el servicio de mensajería

Este objetivo se cumple porque se sabe que el notificador consumió un evento 2 ms después de que lo envió el servicio de mensajería . A diferencia del objetivo 2, para lograr este objetivo no es necesario saber si el evento se procesó completamente ni cuánto tiempo tomó.

Conclusiones

Con base en nuestro análisis de los rastros producidos por la actual autoinstrumentación de OTel, queda claro que:

  • Muchos de estos tramos no son útiles en su forma actual:

    • NGINX está produciendo intervalos relacionados con funciones (como verificación de autorización y servicio de archivos) que no son relevantes para la función que le interesa: el proxy inverso. Sin embargo, en este punto la instrumentación OTel para NGINX no permite omitir tramos irrelevantes, por lo que no se puede hacer nada.
    • Entre los intervalos para los servicios Node.js (los servicios de mensajería y notificación ), algunos parecen relevantes para los objetivos: los intervalos para el análisis de JSON, el controlador de solicitudes y todas las operaciones de base de datos. Algunos de los tramos de middleware (como expressInit y corsMiddleware ) no parecen relevantes y se pueden eliminar.
  • Faltan tramos críticos para lo siguiente:

    • Notificaciones enviadas por el servicio de notificación
    • Una asignación clara entre el evento RabbitMQ enviado desde el servicio de mensajería y el procesado por el servicio notificador

Esto significa que la instrumentación básica cumple el último objetivo:

  • Vea cuánto tiempo tarda el servicio de notificación en comenzar a procesar el evento enviado por el servicio de mensajería

Sin embargo, no hay suficiente información para cumplir los dos primeros objetivos:

  • Comprenda todos los pasos que sigue una solicitud durante el flujo de un nuevo mensaje
  • Tenga confianza en que el flujo se ejecuta de extremo a extremo en menos de cinco segundos en circunstancias normales.

Desafío 4: Optimizar la instrumentación en función de las lecturas de trazas

En este desafío, optimizarás la instrumentación de OTel según los análisis de trazas que realizaste en el Desafío 3. Esto incluye tanto la eliminación de intervalos innecesarios , la creación de nuevos intervalos personalizados y la confirmación de que el evento consumido por el servicio notificador es el generado por el servicio de mensajería.

Eliminar tramos innecesarios

  1. En su editor de texto preferido, abra el archivo tracing.mjs en el directorio de aplicaciones del repositorio de Messenger y agregue lo siguiente al final de la lista de declaraciones de importación en la parte superior:

    constante IGNORED_EXPRESS_SPANS = new Set(["middleware - expressInit", "middleware - corsMiddleware",]);
    

    Esto define un conjunto de nombres de intervalos, derivados de la lista de intervalos que se muestra en la siguiente captura de pantalla de la interfaz de usuario de Jaeger, que se omitirán del seguimiento porque no brindan información útil para este flujo. Puede decidir que otros intervalos enumerados en la captura de pantalla tampoco son necesarios y agregarlos a la lista de IGNORED_EXPRESS_SPANS .

    Captura de pantalla de la GUI de Jaeger que muestra una lista de varios tramos del servicio de mensajería que podrían proporcionar información relevante y, por lo tanto, pueden omitirse del seguimiento.

  2. Agregue filtros a la configuración de instrumentación automática para omitir los intervalos que no desea, modificando la línea resaltada en naranja:

    const sdk = new opentelemetry.NodeSDK({ recurso, traceExporter: new OTLPTraceExporter({ encabezados: {} }), instrumentaciones: [getNodeAutoInstrumentations()], });
    

    A esto:

    const sdk = new opentelemetry.NodeSDK({ recurso, traceExporter: new OTLPTraceExporter({ encabezados: {} }), instrumentaciones: [ getNodeAutoInstrumentations({ "@opentelemetry/instrumentation-express": { ignoreLayers: [ (nombre) => { return IGNORED_EXPRESS_SPANS.has(nombre); }, ], }, }), ], });
    

    La función getNodeAutoInstrumentations hace referencia al conjunto de intervalos definidos en el Paso 1 para filtrarlos del seguimiento generado por @opentelemetry/instrumentation-express . En otras palabras, la declaración de retorno se resuelve como verdadera para un lapso que pertenece a IGNORED_EXPRESS_SPANS , y la declaración ignoreLayers elimina ese lapso del seguimiento.

  3. En la terminal de mensajería, presione Ctrl+c para detener el servicio de mensajería . Luego reinícialo:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Espere unos diez segundos, luego en la terminal del cliente envíe un nuevo mensaje:

    curl -X POST \ -H "Id. de usuario: 2" \
    -H "Tipo de contenido: aplicação/json" \
    -d '{"contenido": "Este es el segundo mensaje"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Revisa los intervalos de mensajería en la interfaz de usuario de Jaeger. Los dos intervalos de middleware , expressInit y corsMiddleware , ya no aparecen (compáralo con la captura de pantalla del Objetivo 2 de la sección "Examinar la mensajería" del Seguimiento del Desafío 3).

    Captura de pantalla de la GUI de Jaeger que muestra que el seguimiento ya no incluye dos intervalos después de cambiar la instrumentación para filtrarlos del seguimiento.

Configurar intervalos personalizados

En esta sección tocas el código de la aplicação por primera vez. La autoinstrumentación genera una gran cantidad de información sin requerir cambios en la aplicação, pero algunos conocimientos solo son posibles mediante la instrumentación de piezas específicas de la lógica empresarial.

Para el nuevo flujo de mensajes que está instrumentando, un ejemplo de esto es rastrear el envío de notificaciones al destinatario del mensaje.

  1. Abra index.mjs en el directorio de la aplicación del repositorio del notificador . Este archivo contiene toda la lógica empresarial del servicio. Agregue la siguiente línea al final de la lista de declaraciones de importación en la parte superior del archivo:

    importar { trace } desde "@opentelemetry/api";
    
  2. Reemplace este código (aproximadamente en la línea 91 del archivo):

    for (let pref of preferences) {
    console.log(
    ``Enviando notificación de nuevo mensaje vía ${pref.address_type} a ${pref.address}`
    );
    }
    

    con:

    const tracer = trace.getTracer("notificador"); // 1 tracer.startActiveSpan( // 2
    "notificación.enviar_a_todos",
    {
    atributos: {
    id_usuario: msg.id_usuario,
    },
    },
    (parentSpan) => {
    for (let pref of preferences) {
    tracer.startActiveSpan( // 3
    "notificación.enviar",
    {
    atributos: { // 4
    tipo_notificación: pref.tipo_dirección,
    id_usuario: pref.id_usuario,
    },
    },
    (span) => {
    console.log(
    ``Enviando notificación de nuevo mensaje vía ${pref.tipo_dirección} a ${pref.dirección}`
    );
    span.end(); // 5
    }
    );
    }
    parentSpan.end(); // 6
    }
    );
    

    El nuevo código hace lo siguiente:

    1. Obtiene el trazador , que es un objeto global para interactuar con los rastros de OTel.
    2. Inicia un nuevo intervalo principal llamado notification.send_all y establece el atributo user_id para identificar al remitente del mensaje.
    3. Ingresa a un bucle en el que se enumeran las preferencias de notificación del destinatario y se crea un nuevo segmento secundario llamado notification.send en notification.send_all . Cada notificación genera un nuevo lapso.
    4. Establece más atributos para el intervalo secundario:

      • notification_type – Uno de sms o correo electrónico
      • user_id – El ID del usuario que recibe la notificación
    5. Cierra cada período de notificación de envío secundario por turno.
    6. Cierra la notificación padre.send_all lapso.

    Tener un span padre garantiza que cada operación de “envío de notificación” se informe incluso si no se descubren preferencias de notificación para el usuario.

  3. En la terminal del notificador, presione Ctrl+c para detener el servicio del notificador . Luego reinícialo:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Espere unos diez segundos, luego en la terminal del cliente envíe un nuevo mensaje:

    curl -X POST \ -H "Id. de usuario: 2" \
    -H "Tipo de contenido: aplicação/json" \
    -d '{"contenido": "Este es el segundo mensaje"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Revisa los intervalos de notificación en la interfaz de usuario de Jaeger. Verás el intervalo principal y dos secundarios, cada uno con una operación de "enviar notificación":

    Captura de pantalla de la GUI de Jaeger que muestra el resultado de definir tres nuevos intervalos en el código para el servicio de notificación

Ahora puedes cumplir completamente el primer y el segundo objetivo, porque puedes ver todos los pasos que sigue una solicitud durante el nuevo flujo de mensajes. Los tiempos en cada tramo exponen cualquier retraso entre cualquiera de estos pasos.

Confirme que el mensajero y el notificador estén manejando el mismo evento

Hay una cosa más que necesitas para tener una comprensión completa del flujo. ¿El evento que está siendo procesado por el servicio notificador es en realidad el enviado por el servicio de mensajería ?

No es necesario realizar ningún cambio explícito para conectar las dos trazas, pero tampoco conviene confiar ciegamente en la magia de la autoinstrumentación.

Con esto en mente, agregue algún código de depuración rápido para verificar que el seguimiento que se inicia en el servicio NGINX sea de hecho el mismo (tenga el mismo ID de seguimiento) que el consumido por el servicio notificador .

  1. Abra el archivo index.mjs en el directorio de aplicaciones del repositorio de Messenger y realice estos cambios:

    • Agregue la siguiente línea al final de la lista de declaraciones de importación en la parte superior:

      importar { trace } desde "@opentelemetry/api";
      
    • Añade las líneas resaltadas en naranja debajo de la línea existente en negro:

      función asíncrona createMessageInConversation(req, res) { const tracer = trace.getActiveSpan(); console.log("TRACE_ID: ", tracer.spanContext().traceId);
      

      Las nuevas líneas imprimen el TRACE_ID desde dentro de la función en Messenger que maneja la creación de un nuevo mensaje.

  2. Abra el archivo index.mjs en el directorio de la aplicación del repositorio del notificador y agregue la línea resaltada en naranja debajo de la línea existente en negro:

    exportar función asíncrona handleMessageConsume(canal, msg, manejadores) { console.log("RABBIT_MQ_MESSAGE: ", msg);
    

    La nueva línea imprime el contenido completo del evento AMQP recibido por el servicio notificador .

  3. Detenga y reinicie los servicios de mensajería y notificación ejecutando estos comandos en las terminales de mensajería y notificación:

    ^cnode --import ./tracing.mjs index.mjs
    
  4. Espere unos diez segundos, luego en la terminal del cliente envíe nuevamente un mensaje:

    curl -X POST \ -H "Id. de usuario: 2" \
    -H "Tipo de contenido: aplicação/json" \
    -d '{"contenido": "Este es el segundo mensaje"}' \
    'http://localhost:8085/conversations/1/messages'
    
  5. Mire los registros de los servicios de mensajería y notificador . El registro del servicio de mensajería incluye una línea como esta, que informa el ID de seguimiento de un mensaje (el ID real será diferente cuando ejecute el tutorial):

    ID DE TRACE:  29377a9b546c50be629c8e64409bbfb5
    
  6. De manera similar, el registro del servicio notificador informa un ID de seguimiento en la salida como este:

    _spanContext: {
    ID de seguimiento: '29377a9b546c50be629c8e64409bbfb5',
      spanId: 'a94e9462a39e6dbf',
      trazar banderas: 1,
    Estado de seguimiento: indefinido
    },
    
  7. Los ID de seguimiento coinciden en la consola, pero como último paso, puede compararlos con el ID de seguimiento en la interfaz de usuario de Jaeger. Abra la interfaz de usuario en el punto final del ID de seguimiento correspondiente (el suyo será diferente, pero en este ejemplo es http://localhost:16686/trace/29377a9b546c50be629c8e64409bbfb5 ) para ver el seguimiento completo. El rastro de Jaeger confirma que:

    • La instrumentación automática de AMQP en el servicio de mensajería agrega este ID de seguimiento como parte de los metadatos cuando se envía el evento.
    • La instrumentación automática de AMQP en el servicio notificador espera esos metadatos y establece el contexto de seguimiento de manera adecuada.

Nota:  En un sistema de producción real, eliminarías el código que agregaste en esta sección una vez que confirmes que el flujo funciona como se espera.

Limpieza de recursos

¡Has creado algunos contenedores e imágenes a lo largo de este tutorial! Utilice estas instrucciones para eliminarlos.

  • Para eliminar cualquier contenedor Docker en ejecución:

    docker rm $(docker stop messenger-lb)
    
  • Para eliminar el servicio de plataforma y los servicios de base de datos de mensajería y notificador :

    cd ~/microservices-march/platform && docker compose down
    cd ~/microservices-march/notifier && docker compose down
    cd ~/microservices-march/messenger && docker compose down
    

Próximos pasos

¡Felicitaciones, has completado el tutorial!

  • Configura la instrumentación de OTel a través de un proxy inverso NGINX y dos servicios Node.js.
  • Analizó con ojo crítico los datos proporcionados por la autoinstrumentación de OTel y agregó algo de telemetría que faltaba para lograr los objetivos del laboratorio de OTel:
    • Obtuvo una visión razonable del flujo de una solicitud específica a través de un sistema de mensajería sin cambiar directamente ningún código de la aplicação .
    • Confirmó que el flujo se ejecutaba de extremo a extremo en menos de cinco segundos en circunstancias normales.

¡Y, sin embargo, apenas has arañado la superficie de cómo podría ser una configuración de rastreo ideal! En un entorno de producción, podría ser útil agregar elementos como intervalos personalizados para cada consulta de base de datos y metadatos adicionales en todos los intervalos que describan detalles de tiempo de ejecución, como el ID del contenedor de cada servicio. También podría implementar los otros dos tipos de datos de OTel (métricas y registro) para obtener una visión completa del estado de su sistema.

Para continuar su educación sobre microservicios, consulte Microservicios de marzo de 2023. En la Unidad 4: Gestione el caos y la complejidad de los microservicios con observabilidad : aprenderá sobre las tres clases principales de datos de observabilidad, la importancia de la infraestructura y la alineación de las aplicaciones, y formas de comenzar a analizar datos profundos.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.