Esta publicación forma parte de una serie de cuatro tutoriales que te ayudarán a poner en práctica los conceptos de Microservices March 2023: Empieza a implementar microservicios:
- Cómo implementar y configurar microservicios
- Cómo gestionar secretos de forma segura en contenedores
- Cómo usar GitHub Actions para automatizar despliegues canary de microservicios
- Cómo usar el rastreo de OpenTelemetry para comprender sus microservicios (este artículo)
Una arquitectura de microservicios ofrece muchas ventajas, como una mayor autonomía de los equipos y una mayor flexibilidad a la hora de escalar y desplegar. Como contrapartida, cuantos más servicios haya en un sistema (y una aplicación de microservicios puede tener decenas o incluso cientos), más difícil resulta tener una visión clara del funcionamiento global del sistema. Como desarrolladores y responsables del mantenimiento de sistemas de software complejos, sabemos que disponer de esa visión clara es de vital importancia. Observabilidad nos proporciona las herramientas necesarias para obtener esa visión de numerosos servicios y de la infraestructura que los sustenta.
En este tutorial, destacamos un tipo de observabilidad muy importante para las aplicaciones de microservicios: el rastreo. Antes de empezar, definamos algunos términos que se utilizan habitualmente al hablar 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 trazas, registros y métricas).
- Monitorización – La capacidad de observar y comprobar el progreso o el estado de un objeto durante un periodo de tiempo. Por ejemplo, puede monitorizar el tráfico que recibe su aplicación durante las horas punta y utilizar esa información para ajustar su escala adecuadamente.
- Telemetría – El proceso de recopilar métricas, trazas y registros, y transferirlos desde su punto de origen a otro sistema para su almacenamiento y análisis. También se refiere a los propios datos.
- Trazado/trazas – Un registro del recorrido de una solicitud o acción a medida que pasa por todos los nodos de un sistema distribuido.
- Intervalo – Un registro dentro de una traza de una operación y sus metadatos asociados. Las trazas se componen de numerosos intervalos anidados.
- Registro de eventos/registros – Un registro de texto con marca de tiempo y metadatos.
- Métrica – Una medición registrada durante la ejecución. Por ejemplo, la cantidad de memoria que utiliza una aplicación en un momento determinado.
Podemos utilizar todos estos conceptos para comprender mejor el rendimiento de nuestros microservicios. El rastreo es una parte especialmente útil de una estrategia de observabilidad, ya que las trazas ofrecen una visión global de lo que sucede en varios componentes, a menudo débilmente acoplados, cuando se realiza una solicitud. También es una forma especialmente eficaz de identificar cuellos de botella en el rendimiento.
Este tutorial utiliza el conjunto de herramientas de rastreo de OpenTelemetry (OTel), un estándar de código abierto independiente de proveedores para recopilar, procesar y exportar datos de telemetría que está ganando popularidad rápidamente. Según el modelo de OTel, una traza divide un flujo de datos, que puede involucrar varios servicios, en una serie de «fragmentos» ordenados cronológicamente que permiten comprender fácilmente:
- Todos los pasos que tuvieron lugar en un «fragmento»
- Cuánto tiempo llevaron todos estos pasos
- Metadatos de cada paso
Si no conoces OTel, consulta «¿Qué es OpenTelemetry?» para obtener una introducción detallada al estándar y conocer los aspectos que deben tenerse en cuenta al implementarlo.
Descripción general del tutorial
Este tutorial se centra en el seguimiento de las operaciones de una aplicación de microservicios con OTel. A lo largo de los cuatro retos del tutorial, aprenderás a rastrear una solicitud a través de tu sistema y a responder preguntas sobre tus microservicios:
- Configurar la instrumentación básica de OTel
- Configura la instrumentación de OTel y la visualización de trazas para todos los servicios
- Aprende a interpretar las trazas de OTel
- Optimiza la instrumentación basándote en la interpretación de las trazas
Estos retos ilustran el proceso que recomendamos seguir al configurar el rastreo por primera vez. Los pasos son:
- Comprenda tanto el sistema como la operación concreta que está instrumentando.
- Decida qué necesita saber del sistema en ejecución.
- Instrumente el sistema de forma «ingenua», es decir, utilice una configuración predeterminada sin intentar descartar la información que no necesita ni recopilar datos personalizados, y evalúe si la instrumentación le ayuda a responder a sus preguntas.
- Ajusta la información que se proporciona para poder responder a esas preguntas más rápidamente.
Nota: En este tutorial pretendemos ilustrar algunos conceptos fundamentales sobre la telemetría, no mostrar la forma correcta de desplegar microservicios en producción. Aunque utiliza una arquitectura real de «microservicios», hay algunas salvedades importantes:
- El tutorial no utiliza ningún framework de orquestación de contenedores, como Kubernetes o Nomad. De este modo, puedes aprender los conceptos relacionados con los microservicios sin atascarte en los detalles específicos de un framework concreto. Los patrones que se presentan aquí se pueden trasladar a un sistema que utilice uno de estos frameworks.
- Los servicios están optimizados para facilitar su comprensión, en lugar de priorizar el rigor de la ingeniería de software. El objetivo es analizar la función de cada servicio en el sistema y sus patrones de comunicación, no los detalles específicos del código. Para obtener más información, consulte los archivos README de cada servicio.
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.

Los dos microservicios son:
- El servicio messenger service – Una API de chat sencilla con capacidad para almacenar mensajes
- El servicio notifier service – Un proceso de escucha que activa eventos para alertar a los usuarios en función de sus preferencias
Los tres componentes de la infraestructura de soporte son:
- NGINX Open Source – Un punto de entrada al servicio messenger y al sistema en su conjunto
- RabbitMQ – Un popular bróker de mensajes de código abierto que permite que los servicios se comuniquen de forma asíncrona
- Jaeger – Un sistema de código abierto de seguimiento distribuido de extremo a extremo para recopilar y visualizar la telemetría de los componentes del sistema que la generan
Dejando OTel de lado por un momento, podemos centrarnos en la secuencia de eventos que estamos rastreando: qué ocurre cuando un usuario envía un nuevo mensaje de chat y se notifica al destinatario.

El flujo se desglosa de la siguiente manera:
- Un usuario envía un mensaje al servicio messenger. El proxy inverso NGINX intercepta el mensaje y lo reenvía a una de las múltiples instancias del servicio messenger.
- El servicio messenger guarda el nuevo mensaje en su base de datos.
- El servicio messenger genera un evento en una cola de mensajes de RabbitMQ denominada chat_queue para indicar que se ha enviado un mensaje. El evento es genérico y no tiene ningún destinatario específico.
- Al mismo tiempo:
- 4a. El servicio messenger devuelve una respuesta al remitente para informarle de que el mensaje se ha enviado correctamente.
- 4b. El servicio notifier detecta el nuevo evento en la cola chat_queue y lo consume.
- El servicio notifier consulta en su base de datos las preferencias de notificación del destinatario del nuevo mensaje.
- El servicio notifier utiliza el método preferido del destinatario para enviar una o varias notificaciones (en este tutorial, las opciones disponibles son SMS y correo electrónico).
Objetivos de telemetría
Al configurar la instrumentación de telemetría, es mejor empezar con una serie de objetivos de instrumentación más concretos que «enviarlo todo y esperar obtener información útil». En este tutorial, tenemos tres objetivos clave de telemetría:
- Comprender todos los pasos por los que pasa una solicitud durante el flujo de un mensaje nuevo
- Tener la certeza de que el flujo se ejecuta de principio a fin en menos de cinco segundos en condiciones normales
- Compruebe cuánto tarda el servicio notifier en empezar a procesar el evento enviado por el servicio messenger (un retraso excesivo podría indicar que el servicio notifier tiene problemas para leer la cola de eventos y que los eventos se están acumulando)
Ten 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 tu propio entorno, necesitas:
- 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 las arquitecturas aarch64 de Linux y los equipos Apple con chip M1 o M2). Las actividades relacionadas con los servicios messenger y notifier funcionan en todas las arquitecturas.
- Conocimientos básicos de la línea de comandos de Linux, JavaScript y
bash(pero se proporciona y explica todo el código y los comandos, por lo que podrás completar el tutorial aunque tus conocimientos sean limitados) - Docker y Docker Compose
- Node.js 19.x o posterior
- Hemos probado la versión 19.x, pero esperamos que las versiones más recientes de Node.js también funcionen.
- Para obtener información detallada sobre la instalación de Node.js, consulta el archivo README del repositorio del servicio messenger. También puedes instalar
asdfpara obtener exactamente la misma versión de Node.js que se utiliza en el tutorial.
curl(ya instalado en la mayoría de los sistemas)- Las tecnologías enumeradas en Arquitectura y flujo de usuario: messenger y notifier (las descargarás en la siguiente sección), NGINX Open Source, Jaeger y RabbitMQ.
Nota: En este tutorial se utiliza el SDK de JavaScript porque los servicios messenger y notifier están escritos en Node.js. También configurará la función de instrumentación automática de OTel (también denominada autoinstrumentación) para hacerse una idea del tipo de información que ofrece OTel. En el tutorial se explica todo lo que necesita saber sobre el SDK de OTel para Node.js, pero, si desea obtener más información, consulte la documentación de OTel.
Configuración
- Inicia una sesión de terminal.
- En su directorio personal, cree el directorio microservices-march y clone en él los repositorios de GitHub de este tutorial. (También puede usar otro nombre de directorio y adaptar las instrucciones según corresponda). Nota: A lo largo del tutorial se omite el símbolo del sistema de la línea de comandos de Linux para facilitar que pueda copiar y pegar los comandos en su terminal. La virgulilla (
~) representa su directorio personal.
mkdir ~/microservices-marchcd ~/microservices-march git clone https://github.com/microservices-march/messenger --branch mm23-metrics-start git clone https://github.com/microservices-march/notifier --branch mm23-metrics-start git clone https://github.com/microservices-march/platform --branch mm23-metrics-startReto 1: Configurar la instrumentación básica de OTel
En este reto, iniciarás el servicio messenger service y configurarás la instrumentación automática de OTel para enviar la telemetría a la consola.
Inicia el servicio messenger
- Cambie al repositorio platform e inicie Docker Compose:
cd ~/microservices-march/platformdocker compose up -d --build- Esto inicia RabbitMQ y Jaeger, que se utilizarán en los siguientes retos.
- La opción «
‑d» indica a Docker Compose que se desvincule de los contenedores una vez que se hayan iniciado (de lo contrario, los contenedores permanecerán vinculados a tu terminal). - La opción
--buildindica a Docker Compose que vuelva a compilar todas las imágenes al iniciarse. Esto garantiza que las imágenes que se están ejecutando se mantengan actualizadas ante cualquier posible cambio en los archivos.
- La opción «
- Ve al directorio app del repositorio messenger e instala Node.js (puedes utilizar otro método si lo prefieres):
cd ~/microservices-march/messenger/appasdf install- Instala las dependencias:
npm install- Inicia la base de datos PostgreSQL para el servicio messenger:
docker compose up -d- Crea el esquema y las tablas de la base de datos e inserta algunos datos iniciales:
npm run refresh-dbConfigurar el envío de la instrumentación automática de OTel a la consola
Con la instrumentación automática de OTel, no es necesario modificar nada en el código de messenger para configurar el rastreo. En lugar de importarse en el propio código de la aplicación, toda la configuración del rastreo se define en un script que se importa en el proceso de Node.js durante la ejecución.
Aquí se configura la instrumentación automática del servicio messenger con el destino más básico para las trazas: la consola. En el Reto 2, se cambiará la configuración para enviar las trazas a Jaeger como recopilador externo.
- Sin salir del directorio app del repositorio messenger, instala los paquetes principales de OTel para Node.js:
npm install @opentelemetry/sdk-node@0.36.0 \ @opentelemetry/auto-instrumentations-node@0.36.4- Estas bibliotecas ofrecen las siguientes funcionalidades: Nota: Una peculiaridad de OTel es que sus SDK de JavaScript están divididos en componentes muy, muy pequeños. Por eso, tendrá que instalar algunos paquetes adicionales incluso para el ejemplo básico de este tutorial. Para saber qué paquetes podría necesitar para realizar tareas de instrumentación distintas de las que se explican en este tutorial, consulte las (excelentes) guías de introducción de OTel y eche un vistazo al repositorio de GitHub de OTel.
@opentelemetry/sdk-node– Generación y exportación de datos de OTel@opentelemetry/auto-instrumentations-node– Configuración automática con los ajustes predeterminados de todas las instrumentaciones más comunes de Node.js
- Crea un archivo nuevo llamado tracing.mjs que contenga el código de instalación y configuración del seguimiento de OTel:
touch tracing.mjs- En tu editor de texto preferido, abre tracing.mjs y añade este código:
//1
import opentelemetry from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
//2
const sdk = new opentelemetry.NodeSDK({
traceExporter: new opentelemetry.tracing.ConsoleSpanExporter(),
instrumentations: [getNodeAutoInstrumentations()],
});
//3
sdk.start();- El código hace lo siguiente:
- Importa las funciones y los objetos necesarios del SDK de OTel.
- Crea una nueva instancia de NodeSDK y la configura para:
- Enviar los spans a la consola (
ConsoleSpanExporter). - Utiliza el autoinstrumentador como conjunto base de instrumentación. Esta instrumentación carga todas las bibliotecas de autoinstrumentación más habituales. En el tutorial, las relevantes son:
@opentelemetry/instrumentation-pgpara la biblioteca de la base de datos PostgreSQL (pg)@opentelemetry/instrumentation-expresspara el framework Express de Node.js@opentelemetry/instrumentation-amqplibpara la biblioteca de RabbitMQ (amqplib)
- Enviar los spans a la consola (
- Inicia el SDK.
- Inicia el servicio messenger, importando el script de instrumentación automática que creaste en el paso 3.
node --import ./tracing.mjs index.mjs- Al cabo de un momento, empieza a aparecer en la consola (el terminal) una gran cantidad de información relacionada con el seguimiento:
...
{
traceId: '9c1801593a9d3b773e5cbd314a8ea89c',
parentId: undefined,
traceState: undefined,
name: 'fs statSync',
id: '2ddf082c1d609fbe',
kind: 0,
timestamp: 1676076410782000,
duration: 3,
attributes: {},
status: { code: 0 },
events: [],
links: []
}
...Nota: Deja abierta la sesión del terminal para volver a utilizarla en el reto 2.
Desafío 2: Configurar la instrumentación de OTel y la visualización de trazas para todos los servicios
Hay muchas herramientas que puedes utilizar para visualizar y analizar trazas, pero en este tutorial se utiliza Jaeger. Jaeger es un framework sencillo y de código abierto para el rastreo distribuido de extremo a extremo, con una interfaz de usuario web integrada para visualizar spans y otros datos de rastreo. La infraestructura proporcionada en el repositorio platform incluye Jaeger (que iniciaste en el paso 1 del reto 1), por lo que puedes centrarte en analizar los datos en lugar de lidiar con herramientas complejas.
Puedes acceder a Jaeger desde el endpoint http://localhost:16686 en tu navegador, pero si accedes ahora mismo, no verás ningún dato sobre tu sistema. Esto se debe a que las trazas que estás recopilando actualmente se envían a la consola. Para ver los datos de las trazas en Jaeger, debes exportarlas utilizando el formato del protocolo OpenTelemetry (OTLP).
En este reto, instrumentarás el flujo principal de usuario configurando la instrumentación para:
- El servicio messenger service, cambiando el destino de las trazas de la consola a Jaeger
- El servicio notifier service
- NGINX
Configurar el envío de la instrumentación automática de OTel a un recopilador externo
Como recordatorio, usar la instrumentación automática de OTel significa que no es necesario modificar nada en el código de messenger para configurar el rastreo. En su lugar, toda la configuración del rastreo se encuentra en un script que se importa en el proceso de Node.js durante la ejecución. Aquí se cambia el destino de las trazas generadas por el servicio messenger, que pasan de enviarse a la consola a enviarse a un recopilador externo (Jaeger en este tutorial).
- Sigue trabajando en el mismo terminal que en el Reto 1 y, en el directorio app del repositorio messenger, instala el paquete de Node.js del exportador OTLP:
npm install @opentelemetry/exporter-trace-otlp-http@0.36.0- La biblioteca
@opentelemetry/exporter-trace-otlp-httpexporta información de trazas en formato OTLP a través de HTTP. Se utiliza para enviar telemetría a un recopilador externo de OTel. - Abre tracing.mjs (que creaste y editaste en el Reto 1) y realiza estos cambios: Nota: Para simplificar, el tutorial presupone que el recopilador se encuentra en la ubicación predeterminada, http://localhost:4318/v1/traces. En un sistema real, es recomendable especificar la ubicación explícitamente.
- Añade esta línea al conjunto de sentencias
importsituadas al principio del archivo:
- Añade esta línea al conjunto de sentencias
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";- Cambia el «exportador» que proporcionas al SDK de OTel, sustituyendo el exportador de consola utilizado en el Reto 1 por uno que pueda enviar datos OTLP a través de HTTP a un recopilador compatible con OTLP. Sustituye:
traceExporter:new opentelemetry.tracing.ConsoleSpanExporter(),- con:
traceExporter: new OTLPTraceExporter({ headers: {} }),- Pulsa
Ctrl+cpara detener el servicio messenger, que iniciaste en este terminal en el paso 4 de Configurar el envío de la instrumentación automática de OTel a la consola. A continuación, reinícialo para utilizar el nuevo exportador configurado en el paso 2:
^cnode --import ./tracing.mjs index.mjs- Inicie una segunda sesión de terminal independiente. (En las instrucciones siguientes, esta se denomina terminal del cliente y la terminal original —utilizada en los pasos 1 y 3—, terminal del mensajero.) Espere unos diez segundos y, a continuación, envíe una solicitud de comprobación de estado al servicio messenger (puede ejecutarla varias veces si desea ver varias trazas):
curl -X GET http://localhost:4000/health- Esperar diez segundos antes de enviar la solicitud facilita la localización de la traza, ya que aparece después de las numerosas trazas que genera la instrumentación automática al iniciarse el servicio.
- En un navegador, acceda a la interfaz de usuario de Jaeger en http://localhost:16686 y compruebe que el exportador OTLP funciona según lo previsto. Haga clic en Buscar en la barra de título y, en el menú desplegable del campo Servicio, seleccione el servicio cuyo nombre empiece por unknown_service. Haga clic en el botón Buscar trazas:

- Haz clic en una traza en el lado derecho de la ventana para mostrar una lista de los spans que contiene. Cada span describe las operaciones, que en ocasiones implican varios servicios, que se ejecutaron como parte de la traza. El span jsonParser de la captura de pantalla muestra cuánto tiempo tardó en ejecutarse la parte
jsonParserdel código de gestión de solicitudes del servicio messenger.
- Como se indicó en el paso 5, el nombre del servicio exportado por el SDK de OTel (unknown_service) no es descriptivo. Para corregirlo, pulsa
Ctrl+cen el terminal de messenger para detener el servicio messenger. A continuación, instala un par de paquetes más de Node.js:
^c npm install @opentelemetry/semantic-conventions@1.10.0 \ @opentelemetry/resources@1.10.0- Estas dos bibliotecas ofrecen las siguientes funcionalidades:
@opentelemetry/semantic-conventions– Define los atributos estándar para las trazas según lo establecido en la especificación de OTel.@opentelemetry/resources– Define un objeto (recurso) que representa la fuente que genera los datos de OTel (en este tutorial, el servicio messenger).
- Abre tracing.mjs en un editor de texto y realiza estos cambios:
- Añade estas líneas al conjunto de sentencias
importsituadas al principio del archivo:
- Añade estas líneas al conjunto de sentencias
import { Resource } from "@opentelemetry/resources";import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";- Crea un
recursollamadomessengerbajo la clave correcta en la especificación de OTel añadiendo la siguiente línea después de la última instrucciónimport:
const resource = new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: "messenger",
});- Pasa el objeto
resourceal constructor de NodeSDK añadiendo la línea resaltada en naranja entre las líneas en negro:
const sdk = new opentelemetry.NodeSDK({ resource,
traceExporter: new OTLPTraceExporter({ headers: {} }),
instrumentations: [getNodeAutoInstrumentations()],
});- Reinicia el servicio messenger:
node --import ./tracing.mjs index.mjs- Espera unos diez segundos y, a continuación, en el terminal del cliente (que abriste en el paso 4), envía otra solicitud de comprobación de estado al servidor (puedes ejecutar el comando varias veces si quieres ver varias trazas):
curl -X GET http://localhost:4000/health- Nota: Deja abierto el terminal del cliente para volver a utilizarlo en la siguiente sección y el terminal del mensajero para volver a utilizarlo en el Reto 3.
- Confirma que aparece un nuevo servicio llamado «messenger» en la interfaz de usuario de Jaeger en el navegador (puede tardar unos segundos y quizá tengas que actualizar la interfaz de usuario de Jaeger):

- Selecciona messenger en el menú desplegable Servicio y haz clic en el botón Buscar trazas para ver todas las trazas recientes procedentes del servicio messenger (la captura de pantalla muestra las 2 más recientes de un total de 20):

- Haz clic en una traza para mostrar los spans que contiene. Cada span está correctamente etiquetado como procedente del servicio messenger:

Configurar la instrumentación automática de OTel para el servicio notifier
Ahora, inicia y configura la instrumentación automática para el servicio notifier, ejecutando básicamente los mismos comandos que en las dos secciones anteriores para el servicio messenger.
- Abre una nueva sesión de terminal (denominada «terminal de notifier» en los pasos siguientes). Ve al directorio app del repositorio notifier e instala Node.js (puedes utilizar otro método si lo prefieres):
cd ~/microservices-march/notifier/appasdf install- Instala las dependencias:
npm install- Inicia la base de datos PostgreSQL para el servicio notifier:
docker compose up -d- Crea el esquema y las tablas de la base de datos e inserta algunos datos iniciales:
npm run refresh-db- Instale los paquetes de OTel para Node.js (para obtener una descripción de lo que hacen los paquetes, consulte los pasos 1 y 3 de «Configurar el envío de la instrumentación automática de OTel 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- Crea un archivo nuevo llamado «tracing.mjs»:
touch tracing.mjs- En tu editor de texto preferido, abre tracing.mjs y añade el siguiente script para poner en marcha el SDK de OTel:
import opentelemetry from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
const resource = new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "notifier",
});
const sdk = new opentelemetry.NodeSDK({
resource,
traceExporter: new OTLPTraceExporter({ headers: {} }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();- Nota: Este script es exactamente igual que el del servicio messenger, salvo que el valor del campo
SemanticResourceAttributes.SERVICE_NAMEesnotifier. - Inicia el servicio notifier con la instrumentación automática de OTel:
node --import ./tracing.mjs index.mjs- Espera unos diez segundos y, a continuación, envía desde el terminal del cliente una solicitud de comprobación de estado al servicio notifier. Este servicio escucha en el puerto 5000 para evitar conflictos con el servicio messenger, que escucha en el puerto 4000:
curl http://localhost:5000/health- Nota: Deja abiertas las terminales del cliente y del notificador para volver a utilizarlas en el reto 3.
- Confirma que aparece un nuevo servicio llamado «notifier» en la interfaz de usuario de Jaeger en el navegador:

Configurar la instrumentación de OTel en NGINX
En NGINX, el seguimiento se configura manualmente en lugar de utilizar el método de instrumentación automática de OTel. Actualmente, la forma más habitual de instrumentar NGINX con OTel es utilizar un módulo escrito en C. Los módulos de terceros son una parte importante del ecosistema de NGINX, pero su configuración requiere cierto trabajo. Este tutorial se encarga de configurarlos. Para obtener más información, consulte Compilación de módulos dinámicos de terceros para NGINX y NGINX Plus en nuestro blog.
- Inicie una nueva sesión de terminal (el terminal de NGINX), cambie al directorio raíz del repositorio messenger 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 load-balancer cd load-balancer touch Dockerfile touch nginx.conf touch opentelemetry_module.conf- En tu editor de texto preferido, abre Dockerfile y añade lo siguiente (los comentarios explican qué hace cada línea, pero puedes compilar y ejecutar el contenedor de Docker sin entenderlo todo):
FROM --platform=amd64 nginx:1.23.1
# Replace the nginx.conf file with our own
COPY nginx.conf /etc/nginx/nginx.conf
# Define the version of the NGINX OTel module
ARG OPENTELEMETRY_CPP_VERSION=1.0.3
# Define the search path for shared libraries used when compiling and running NGINX
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/opentelemetry-webserver-sdk/sdk_lib/lib
# 1. Download the latest version of Consul template and the OTel C++ web server module, otel-webserver-module
ADD https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/download/webserver%2Fv${OPENTELEMETRY_CPP_VERSION}/opentelemetry-webserver-sdk-x64-linux.tgz /tmp
RUN apt-get update \
&& apt-get install -y --no-install-recommends dumb-init unzip \
# 2. Extract the module files
&& tar xvfz /tmp/opentelemetry-webserver-sdk-x64-linux.tgz -C /opt \
&& rm -rf /tmp/opentelemetry-webserver-sdk-x64-linux.tgz \
# 3. Install and add the 'load_module' directive at the top of the main NGINX configuration file
&& /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. Copy in the configuration file for the NGINX OTel module
COPY opentelemetry_module.conf /etc/nginx/conf.d/opentelemetry_module.conf
EXPOSE 8085
STOPSIGNAL SIGQUIT- Abre nginx.conf y añade lo siguiente:
events {}
http {
include /etc/nginx/conf.d/opentelemetry_module.conf;
upstream messenger {
server localhost:4000;
}
server {
listen 8085;
location / {
proxy_pass http://messenger;
}
}
}- Este archivo de configuración de NGINX extremadamente básico indica a NGINX que: Nota: Esta configuración se aproxima bastante a la configuración real de NGINX como proxy inverso y equilibrador de carga en un entorno de producción. La única diferencia importante es que el argumento de la directiva
serverdel bloqueupstreamsuele ser un nombre de dominio o una dirección IP en lugar delocalhost.- Configure un grupo de servidores upstream llamado «messenger» que represente el grupo de instancias del servicio «messenger»
- Escuchar las solicitudes HTTP en el puerto 8085
- Reenviar todas las solicitudes entrantes cuyas rutas comiencen por / (es decir, todas las solicitudes entrantes) al servidor upstream messenger upstream
- Abre opentelemetry_module.conf y añade lo siguiente:
NginxModuleEnabled ON;NginxModuleOtelSpanExporter otlp;
NginxModuleOtelExporterEndpoint localhost:4317;
NginxModuleServiceName messenger-lb;
NginxModuleServiceNamespace MicroservicesMarchDemoArchitecture;
NginxModuleServiceInstanceId DemoInstanceId;
NginxModuleResolveBackends ON;
NginxModuleTraceAsError ON;- Crea una imagen de Docker que contenga NGINX y el módulo OTel de NGINX:
docker build -t messenger-lb .- Inicia el contenedor de Docker para el proxy inverso y el balanceador de carga NGINX:
docker run --rm --name messenger-lb -p 8085:8085 --network="host" messenger-lb- En el terminal del cliente, envía una solicitud de comprobación de estado al servicio messenger a través del proxy inverso y balanceador de carga NGINX (no es necesario esperar antes de enviar esta solicitud):
curl http://localhost:8085/health- Nota: Deja abiertas las terminales de NGINX y del cliente para volver a utilizarlas en el reto 3.
- En el navegador, confirme que el nuevo servicio messenger-lb aparece en la interfaz de usuario de Jaeger junto con los servicios que inició anteriormente. Es posible que tenga que volver a cargar la interfaz de usuario de Jaeger en el navegador.

Desafío 3: Aprende a interpretar trazas de OTel
En «Arquitectura y flujo de usuario», describimos las etapas del flujo de usuario, pero, a modo de resumen:
- Un usuario inicia una conversación enviando un mensaje a otro usuario.
- El proxy inverso NGINX intercepta el mensaje y lo reenvía al servicio messenger.
- El servicio messenger guarda el mensaje en su base de datos y, a continuación, envía un evento a través de RabbitMQ.
- El servicio notifier consume ese evento, consulta las preferencias de notificación del destinatario (el segundo usuario) y le envía una notificación mediante el método que haya elegido.
Y los objetivos de implementar la telemetría son:
- Comprender todos los pasos por los que pasa una solicitud para completar el nuevo flujo de mensajes.
- Tenga la certeza de que el flujo se ejecuta de principio a fin en menos de cinco segundos en condiciones normales.
- Comprueba cuánto tarda el servicio notifier en empezar a procesar el evento enviado por el servicio messenger.
En este reto, aprenderá a evaluar si las trazas generadas por la instrumentación de OTel cumplen los objetivos mencionados anteriormente. Primero, probará el sistema y creará algunas trazas. A continuación, examinará la traza de un flujo de mensajes y las secciones generadas por NGINX, el servicio messenger service, y el servicio notifier service.
Crear datos de trazas
En el terminal del cliente, configura una conversación y envía un par de mensajes entre dos usuarios:
curl -X POST \ -H "Content-Type: application/json" \ -d '{"participant_ids": [1, 2]}' \ 'http://localhost:8085/conversations' curl -X POST \ -H "User-Id: 1" \ -H "Content-Type: application/json" \ -d '{"content": "This is the first message"}' \ 'http://localhost:8085/conversations/1/messages' curl -X POST \ -H "User-Id: 2" \ -H "Content-Type: application/json" \ -d '{"content": "This is the second message"}' \ 'http://localhost:8085/conversations/1/messages'El servicio notifier genera una salida como la siguiente, que aparece en el terminal del notificador:
Received new_message: {"type":"new_message","channel_id":1,"user_id":1,"index":1,"participant_ids":[1,2]}Sending notification of new message via sms to 12027621401
Received new_message: {"type":"new_message","channel_id":1,"user_id":2,"index":2,"participant_ids":[1,2]}
Sending notification of new message via email to the_hotstepper@kamo.ze
Sending notification of new message via sms to 19147379938Prepárate para leer las trazas
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 trazas. Aparecerá una lista de trazas desde el principio del flujo. Haga clic en cualquier traza para ver sus detalles, como se muestra en esta captura de pantalla:

Haz clic en distintos elementos y explora un poco. Antes de continuar, piensa en cómo la información de las trazas contribuye a alcanzar los objetivos de instrumentación indicados en la introducción del Reto 3. Entre las preguntas relevantes se incluyen:
- ¿Qué información ayuda a alcanzar los objetivos?
- ¿Qué información falta?
- ¿Qué información no es relevante?
Examine la sección de NGINX (messenger-lb) de la traza
Objetivo 1: Ver todos los pasos por los que pasa una solicitud en el nuevo flujo de mensajes
Empiece por el tramo de NGINX, que contiene 11 tramos secundarios dentro del tramo principal. Dado que la configuración actual de NGINX es muy sencilla, los tramos secundarios no resultan especialmente interesantes y se limitan a mostrar el tiempo empleado en cada etapa del ciclo de vida del procesamiento de solicitudes de NGINX. Sin embargo, el tramo principal (el primero de todos) ofrece algunos datos interesantes:

- En Etiquetas se muestran los siguientes atributos: En conjunto, estos tres datos indican lo siguiente: «Se envió una solicitud
POSTa/conversations/1/messagesy la respuesta fue201(creado correctamente)». Esto se corresponde con los pasos 1 y 4a de Arquitectura y flujo de usuario).http.methodcampo –POST(en términos de REST, esto significa creación)http.status_codecampo –201(indica que la creación se ha realizado correctamente)http.targetcampo –conversations/1/messages(el endpoint de mensajes)
- En Proceso, el campo
webengine.namemuestra que esta es la parte de la solicitud correspondiente a NGINX.
Además, dado que los spans de messenger y notifier están anidados dentro del span conversations/1 de messenger-lb (como se muestra en la captura de pantalla de Prepararse para leer las trazas), se puede determinar que la solicitud enviada al servicio messenger a través del proxy inverso NGINX pasó por todos los componentes previstos del flujo.
Esta información cumple el objetivo, ya que permite comprobar que el proxy inverso NGINX formó parte del flujo.
Objetivo 2: Verificar que el flujo se ejecuta en menos de cinco segundos
En la lista de spans con la etiqueta «messenger-lb», consulta el span más reciente (se encuentra al final de la lista) para ver cuánto tardó la parte de NGINX de la solicitud. En la captura de pantalla, el span comenzó a los 589 microsegundos (µs) y duró 24 µs, lo que significa que la operación completa del proxy inverso tardó solo 613 µs, es decir, unos 0,6 milisegundos (ms). (Por supuesto, los valores exactos serán diferentes cuando realices el tutorial).

En una configuración como esta, por lo general los valores solo resultan útiles en relación con otras mediciones y varían de un sistema a otro. Sin embargo, en este caso está claro que esta operación no corre el riesgo de acercarse a los cinco segundos de duración.
Esta información cumple el objetivo, ya que permite comprobar que las operaciones de NGINX no tardaron ni de lejos cinco segundos. Si hay alguna operación muy lenta en el flujo, debe de producirse más adelante.
Objetivo 3: comprobar cuánto tarda el servicio notifier en leer el evento enviado por el servicio messenger
La capa de proxy inverso de NGINX no incluye ninguna información al respecto, por lo que puede pasar a los intervalos de messenger.
Examine la sección messenger de la traza
Objetivo 1: Ver todos los pasos por los que pasa una solicitud en el nuevo flujo de mensajes
La sección del servicio messenger de la traza contiene otros 11 spans. De nuevo, la mayoría de los spans secundarios corresponden a los pasos básicos que utiliza el framework Express al procesar una solicitud y no resultan muy interesantes. Sin embargo, el span principal (el primero de todos) vuelve a aportar información interesante:

En Etiquetas se muestran los siguientes atributos:
http.methodcampo –POST(de nuevo, en términos de REST, esto significa creación)http.routecampo –/conversations/:conversationId/messages(la ruta de mensajes)http.targetcampo –/conversations/1/messages(el endpoint de mensajes)
Esta información cumple el objetivo porque nos muestra que el servicio messenger formó parte del flujo y que el endpoint al que se accedió fue el de mensajes nuevos.
Objetivo 2: Verificar que el flujo se ejecuta en menos de cinco segundos
Como se muestra en la siguiente captura de pantalla, la parte messenger de la traza comenzó en 1,28 ms y terminó en 36,28 ms, con un tiempo total de 35 ms. La mayor parte de ese tiempo se dedicó a analizar el 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 durante el proceso de escritura del mensaje también se realizan varias consultas SQL. Esto, a su vez, sugiere que quizá convenga ampliar la configuración de instrumentación automática para registrar la duración de dichas consultas. (El tutorial no muestra esta instrumentación adicional, pero en el Reto 4 se crean manualmente spans que, a su vez, pueden utilizarse para encapsular consultas a la base de datos).

Esta información cumple el objetivo porque demuestra que las operaciones de mensajería no tardan ni de lejos cinco segundos. Si hay una operación muy lenta en el flujo, debe de producirse más adelante.
Objetivo 3: comprobar cuánto tarda el servicio notifier en leer el evento enviado por el servicio messenger
Al igual que los spans de NGINX, los spans de messenger no incluyen esta información, por lo que puedes pasar a los spans de notifier.
Examine la sección notifier de la traza
Objetivo 1: Ver todos los pasos por los que pasa una solicitud en el nuevo flujo de mensajes
La sección notifier de la traza contiene solo dos spans:

- El intervalo
chat_queueprocessconfirma que el servicio notifier procesó un evento de la cola de mensajes chat_queue message queue - El span
pg-pool.connectmuestra que, tras procesar el evento, el servicio notifier estableció algún tipo de conexión con su base de datos
La información disponible en estos spans solo permite alcanzar parcialmente el objetivo de comprender cada paso. Se puede ver que el servicio notifier llegó a consumir el evento de la cola, pero no se sabe si:
- La notificación del mensaje enviada por este servicio corresponde al evento emitido por el servicio messenger service
- Las notificaciones pertinentes del mensaje se enviaron correctamente al destinatario del mensaje
Esto indica que debe hacer lo siguiente para comprender plenamente el flujo del servicio notifier:
- Instrumenta manualmente los spans que muestran el envío de una notificación
- Asegúrate de que haya una conexión explícita entre el evento enviado por el servicio messenger y el evento consumido por el servicio notifier, en forma de un ID de traza
Objetivo 2: Verificar que el flujo se ejecuta en menos de cinco segundos
Al observar la duración total de los intervalos del servicio notifier, se aprecia que la solicitud pasó 30,77 ms en la sección notifier del flujo. Sin embargo, como no hay intervalos que indiquen el «final» de todo el flujo (el envío de notificaciones al destinatario), no se puede determinar la duración total de esta sección del flujo ni el tiempo total que tarda en completarse la operación.
Objetivo 3: comprobar cuánto tarda el servicio notifier en leer el evento enviado por el servicio messenger
Sin embargo, puede ver que un intervalo de chat_queue de tipo process del servicio notifier comenzó a los 6,12 ms, 2 ms después de que comenzara un intervalo de chat_queue de tipo send del servicio messenger a los 4,12 ms.

Este objetivo se cumple porque sabes que el servicio notifier consumió un evento 2 ms después de que lo enviara el servicio messenger. A diferencia del objetivo 2, para alcanzar este objetivo no necesitas saber si el evento se procesó por completo ni cuánto tiempo tardó.
Conclusiones
Según nuestro análisis de las trazas generadas por la instrumentación automática actual de OTel, está claro que:
- Muchos de estos spans no resultan útiles en su forma actual:
- NGINX está generando spans relacionados con funciones —como la comprobación de autorizaciones y el servicio de archivos— que no son relevantes para la función que le interesa: el proxy inverso. Sin embargo, actualmente la instrumentación OTel para NGINX no permite omitir los spans irrelevantes, por lo que no se puede hacer nada.
- Entre los spans de los servicios de Node.js (los servicios messenger y notifier), algunos parecen relevantes para los objetivos: los spans correspondientes al análisis de JSON,
requesthandlery todas las operaciones de base de datos. Algunos de los spans del middleware (comoexpressInitycorsMiddleware) no parecen relevantes y se pueden eliminar.
- Faltan spans críticos para lo siguiente:
- Notificaciones enviadas por el servicio notifier service
- Una correspondencia clara entre el evento de RabbitMQ enviado por el servicio messenger y el procesado por el servicio notifier service
Esto significa que la instrumentación básica cumple el último objetivo:
- Comprueba cuánto tarda el servicio notifier en empezar a procesar el evento enviado por el servicio messenger service
Sin embargo, no hay suficiente información para cumplir los dos primeros objetivos:
- Comprender todos los pasos por los que pasa una solicitud durante el nuevo flujo de mensajes
- Tener la certeza de que el flujo se ejecuta de principio a fin en menos de cinco segundos en circunstancias normales
Desafío 4: Optimizar la instrumentación a partir de las lecturas de trazas
En este reto, optimizarás la instrumentación de OTel basándote en los análisis de trazas que realizaste en el reto 3. Esto incluye tanto eliminar spans innecesarios, crear nuevos spans personalizados como confirmar que el evento que consume el servicio de notificaciones es el generado por el servicio de mensajería.
Eliminar spans innecesarios
- En el editor de texto que prefiera, abra el archivo tracing.mjs del directorio app del repositorio messenger y añada lo siguiente al final de la lista de sentencias de importación situada en la parte superior:
const IGNORED_EXPRESS_SPANS = new Set([ "middleware - expressInit",
"middleware - corsMiddleware",
]);- Esto define un conjunto de nombres de spans, extraídos de la lista de spans que se muestra en la siguiente captura de pantalla de la interfaz de Jaeger, que se omitirán de la traza porque no aportan información útil para este flujo. Puede que decida que tampoco se necesitan otros spans incluidos en la captura de pantalla y los añada a la lista de
IGNORED_EXPRESS_SPANS.
- Añada filtros a la configuración de instrumentación automática para omitir los spans que no desee cambiando la línea resaltada en naranja:
const sdk = new opentelemetry.NodeSDK({ resource,
traceExporter: new OTLPTraceExporter({ headers: {} }),
instrumentations: [getNodeAutoInstrumentations()],
});- a esto:
const sdk = new opentelemetry.NodeSDK({ resource,
traceExporter: new OTLPTraceExporter({ headers: {} }),
instrumentations: [ getNodeAutoInstrumentations({ "@opentelemetry/instrumentation-express": { ignoreLayers: [ (name) => { return IGNORED_EXPRESS_SPANS.has(name); }, ], }, }), ],
});- La función
getNodeAutoInstrumentationshace referencia al conjunto de spans definido en el paso 1 para excluirlos de la traza generada por@opentelemetry/instrumentation-express. En otras palabras, la instrucciónreturnse evalúa comotruepara un span que pertenece aIGNORED_EXPRESS_SPANS, y la instrucciónignoreLayerselimina ese span de la traza. - En el terminal de messenger, pulsa
Ctrl+cpara detener el servicio messenger. A continuación, reinícialo:
^cnode --import ./tracing.mjs index.mjs- Espera unos diez segundos y, a continuación, envía un mensaje nuevo desde el terminal del cliente:
curl -X POST \ -H "User-Id: 2" \ -H "Content-Type: application/json" \ -d '{"content": "This is the second message"}' \ 'http://localhost:8085/conversations/1/messages'- Vuelve a comprobar los spans de messenger en la interfaz de usuario de Jaeger. Los dos spans de
middleware,expressInitycorsMiddleware, ya no aparecen (puedes compararlo con la captura de pantalla del Objetivo 2 de Examinar la sección messenger de la traza en el Reto 3.
Configurar spans personalizados
En esta sección, trabajará por primera vez con el código de la aplicación. La instrumentación automática genera una gran cantidad de información sin necesidad de modificar la aplicación, pero algunos datos solo pueden obtenerse instrumentando partes específicas de la lógica de negocio.
En el nuevo flujo de mensajes que está instrumentando, un ejemplo de ello es el seguimiento del envío de notificaciones al destinatario del mensaje.
- Abre index.mjs en el directorio app del repositorio notifier. Este archivo contiene toda la lógica de negocio del servicio. Añade la siguiente línea al final de la lista de sentencias
importsituada al principio del archivo:
import { trace } from "@opentelemetry/api";- Sustituye este código (aproximadamente en la línea 91 del archivo):
for (let pref of preferences) {
console.log(
`Sending notification of new message via ${pref.address_type} to ${pref.address}`
);
}- con:
const tracer = trace.getTracer("notifier"); // 1tracer.startActiveSpan( // 2
"notification.send_all",
{
attributes: {
user_id: msg.user_id,
},
},
(parentSpan) => {
for (let pref of preferences) {
tracer.startActiveSpan( // 3
"notification.send",
{
attributes: { // 4
notification_type: pref.address_type,
user_id: pref.user_id,
},
},
(span) => {
console.log(
`Sending notification of new message via ${pref.address_type} to ${pref.address}`
);
span.end(); // 5
}
);
}
parentSpan.end(); // 6
}
);- El nuevo código hace lo siguiente: tener un span principal garantiza que se registre cada operación de «envío de notificación», incluso si no se encuentra ninguna preferencia de notificación para el usuario.
- Obtiene el objeto
tracer, que es un objeto global para interactuar con las trazas de OTel. - Inicia un nuevo intervalo principal llamado «
notification.send_all» y establece el atributo «user_id» para identificar al remitente del mensaje. - Entra en un bucle en el que se enumeran las preferencias de notificación del destinatario y se crea un nuevo intervalo secundario llamado
notification.sendbajonotification.send_all. Cada notificación genera un nuevo intervalo. - Establece más atributos para el span secundario:
notification_type– Uno de los siguientes:smsoemailuser_id– El ID del usuario que recibe la notificación
- Cierra sucesivamente cada tramo secundario
notification.send. - Cierra el span principal
notification.send_all.
- Obtiene el objeto
- En el terminal del notificador, pulsa
Ctrl+cpara detener el servicio notifier. A continuación, reinícialo:
^cnode --import ./tracing.mjs index.mjs- Espera unos diez segundos y, a continuación, envía un nuevo mensaje desde el terminal del cliente:
curl -X POST \ -H "User-Id: 2" \ -H "Content-Type: application/json" \ -d '{"content": "This is the second message"}' \ 'http://localhost:8085/conversations/1/messages'- Vuelve a comprobar los intervalos de notifier en la interfaz de usuario de Jaeger. Verás el intervalo principal y dos intervalos secundarios, cada uno con una operación «send notification»:

Ahora puede cumplir plenamente el primer y el segundo objetivo, ya que puede ver todos los pasos por los que pasa una solicitud durante el nuevo flujo de mensajes. Los tiempos de cada tramo revelan cualquier retraso entre estos pasos.
Confirma que el mensajero y el notificador gestionan el mismo evento
Hay una cosa más que necesitas para comprender plenamente el flujo. ¿El evento que está procesando el servicio notifier es realmente el que ha enviado el servicio messenger?
No tienes que hacer ningún cambio explícito para conectar las dos trazas, pero tampoco conviene confiar ciegamente en la magia de la instrumentación automática.
Teniendo esto en cuenta, añade un breve código de depuración para comprobar que la traza que se inicia en el servicio NGINX es realmente la misma (tiene el mismo ID de traza) que la que consume el servicio notifier.
- Abre el archivo «index.mjs» del directorio «app» del repositorio «messenger» y realiza estos cambios:
- Añade la siguiente línea al final de la lista de sentencias de importación situada en la parte superior:
import { trace } from "@opentelemetry/api";- Añade las líneas resaltadas en naranja debajo de la línea existente en negro:
async function createMessageInConversation(req, res) {
const tracer = trace.getActiveSpan(); console.log("TRACE_ID: ", tracer.spanContext().traceId);- Las nuevas líneas muestran el
TRACE_IDdesde dentro de la función de messenger que se encarga de crear un nuevo mensaje.
- Abre el archivo index.mjs del directorio app del repositorio notifier y añade la línea resaltada en naranja debajo de la línea existente en negro:
export async function handleMessageConsume(channel, msg, handlers) { console.log("RABBIT_MQ_MESSAGE: ", msg);- La nueva línea muestra el contenido completo del evento AMQP recibido por el servicio notifier.
- Detenga y reinicie los servicios messenger y notifier ejecutando estos comandos en los terminales de messenger y notifier:
^cnode --import ./tracing.mjs index.mjs- Espera unos diez segundos y, a continuación, vuelve a enviar un mensaje desde el terminal del cliente:
curl -X POST \ -H "User-Id: 2" \ -H "Content-Type: application/json" \ -d '{"content": "This is the second message"}' \ 'http://localhost:8085/conversations/1/messages'- Consulta los registros de los servicios messenger y notifier. El registro del servicio messenger incluye una línea como esta, que muestra el ID de traza de un mensaje (el ID real será diferente cuando sigas el tutorial):
TRACE_ID: 29377a9b546c50be629c8e64409bbfb5- Del mismo modo, el registro del servicio notifier muestra un ID de seguimiento en una salida como esta:
_spanContext: {
traceId: '29377a9b546c50be629c8e64409bbfb5',
spanId: 'a94e9462a39e6dbf',
traceFlags: 1,
traceState: undefined
},- Los ID de traza coinciden en la consola, pero, como último paso, puedes compararlos con el ID de traza de la interfaz de usuario de Jaeger. Abre la interfaz de usuario en el endpoint del ID de traza correspondiente (el tuyo será diferente, pero en este ejemplo es http://localhost:16686/trace/29377a9b546c50be629c8e64409bbfb5) para ver la traza completa. La traza de Jaeger confirma que:
- La instrumentación automática de AMQP en el servicio messenger añade este ID de traza como parte de los metadatos cuando se envía el evento.
- La instrumentación automática de AMQP del servicio notifier espera esos metadatos y configura adecuadamente el contexto de la traza.
Nota: En un sistema de producción real, eliminaría el código que ha añadido en esta sección una vez que haya confirmado que el flujo funciona según lo previsto.
Limpieza de recursos
¡A lo largo de este tutorial has creado varios contenedores e imágenes! Sigue estas instrucciones para eliminarlos.
- Para eliminar cualquier contenedor de Docker que esté en ejecución:
docker rm $(docker stop messenger-lb)- Para eliminar el servicio platform y los servicios de base de datos messenger y notifier:
cd ~/microservices-march/platform && docker compose down cd ~/microservices-march/notifier && docker compose down cd ~/microservices-march/messenger && docker compose downPróximos pasos
¡Enhorabuena, has completado el tutorial!
- Has configurado la instrumentación de OTel en un proxy inverso NGINX y dos servicios de Node.js.
- Analizaste de forma crítica los datos proporcionados por la instrumentación automática de OTel y añadiste algunos datos de telemetría que faltaban para alcanzar los objetivos del laboratorio de OTel:
- Obtuvo una visión razonablemente clara del recorrido de una solicitud específica a través de un sistema de mensajería sin modificar directamente el código de la aplicación.
- Confirmaste que, en circunstancias normales, el flujo se ejecutaba de principio a fin en menos de cinco segundos.
Y, aun así, ¡apenas has empezado a descubrir cómo podría ser una configuración de trazabilidad ideal! En un entorno de producción, quizá te interese añadir elementos como spans personalizados para cada consulta a la base de datos y metadatos adicionales en todos los spans que describan detalles del entorno de ejecución, como el ID del contenedor de cada servicio. También podrías implementar los otros dos tipos de datos de OTel (métricas y registros) para obtener una visión completa del estado de tu sistema.
Para seguir aprendiendo sobre microservicios, consulta Microservices March 2023. En la Unidad 4: Gestiona el caos y la complejidad de los microservicios mediante la observabilidad, conocerás las tres clases principales de datos de observabilidad, la importancia de alinear la infraestructura y las aplicaciones, y distintas formas de empezar a analizar datos en profundidad.

Sobre el autor
Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.