Trazabilidad

Trazabilidad en sistemas distribuidos: correlation IDs, tracing distribuido y logging estructurado para seguir el recorrido de cada operación entre servicios.

Por qué la trazabilidad es esencial

En un monolito, seguir el flujo de una operación es relativamente simple: todo ocurre en el mismo proceso, con un único log. En un sistema distribuido, una sola acción del usuario puede atravesar 5 o más servicios, cada uno con sus propios logs, tiempos y posibles fallos.

Sin trazabilidad, diagnosticar un problema se convierte en buscar una aguja en un pajar distribuido. La trazabilidad permite reconstruir el camino completo de una operación a través de todos los servicios involucrados.

Los tres pilares de la trazabilidad

1. Correlation ID

Un identificador único que acompaña a una operación desde su origen hasta el último servicio que la procesa. Todos los logs, eventos y métricas relacionados con esa operación comparten el mismo correlation ID.

2. Distributed Tracing

Un sistema que registra el tiempo y la relación entre las operaciones en cada servicio, permitiendo visualizar el flujo completo como un árbol de spans.

3. Logging estructurado

Logs en formato estructurado (JSON) que incluyen el correlation ID y metadata contextual, facilitando la búsqueda y correlación.

Correlation ID en acción

sequenceDiagram
    participant FE as Frontend
    participant GW as API Gateway
    participant BFF as BFF
    participant MS1 as ms-orders
    participant MS2 as ms-inventory
    participant EB as Event Bus

    FE->>GW: POST /orders (X-Correlation-ID: abc-123)
    GW->>BFF: Forward (X-Correlation-ID: abc-123)
    BFF->>MS1: Crear orden (X-Correlation-ID: abc-123)
    MS1->>EB: OrderPlaced (correlationId: abc-123)
    EB->>MS2: OrderPlaced (correlationId: abc-123)
    MS2->>MS2: Reservar stock (log: abc-123)

Cómo se propaga el Correlation ID

  1. El frontend genera un UUID único al iniciar la operación (o lo genera el API Gateway si no viene)
  2. Se incluye en el header HTTP X-Correlation-ID
  3. Cada servicio lo extrae del request entrante y lo incluye en:
    • Todos sus logs
    • Todas las llamadas HTTP salientes
    • Todos los eventos que publica al Event Bus
    • Todas las métricas que registra
  4. Los consumidores de eventos lo extraen del payload del evento

Regla fundamental

Nunca generar un nuevo correlation ID en un servicio intermedio. Si un servicio recibe un request sin correlation ID, puede generar uno. Pero si ya viene uno, debe propagarlo tal cual.

Distributed Tracing

El tracing distribuido va más allá del correlation ID. Registra la estructura temporal del flujo: qué servicio llamó a cuál, cuánto tardó cada operación y dónde se produjo un error.

Conceptos clave

Trace: representa el flujo completo de una operación, desde el origen hasta el final. Un trace contiene múltiples spans.

Span: representa una operación individual dentro de un servicio. Tiene un inicio, un fin, un nombre y metadata.

Parent-Child: los spans se organizan en un árbol. El span del BFF es padre del span del microservicio que invoca.

Ejemplo de un trace

Trace: abc-123
├── [Gateway] POST /orders (5ms)
│   └── [BFF] createOrder (45ms)
│       ├── [ms-orders] createOrder (30ms)
│       │   └── [DB] INSERT INTO orders (8ms)
│       └── [ms-orders] publishEvent (5ms)
└── [ms-inventory] handleOrderPlaced (20ms)  ← asíncrono
    └── [DB] UPDATE stock (6ms)

Este trace muestra que:

  • El request total tardó 50ms (Gateway → BFF → ms-orders)
  • La operación de base de datos en ms-orders tardó 8ms
  • El procesamiento asíncrono en inventario tardó 20ms adicionales

Herramientas de tracing

Las herramientas más comunes para tracing distribuido son:

HerramientaTipoCaracterísticas
JaegerOpen sourceVisualización de traces, análisis de latencia
ZipkinOpen sourceLigero, buena integración con Spring
OpenTelemetryEstándarVendor-neutral, combina traces, métricas y logs
AWS X-RayManagedIntegrado con servicios AWS
Datadog APMSaaSTraces + métricas + logs en una plataforma

OpenTelemetry se está convirtiendo en el estándar de facto porque es vendor-neutral y permite cambiar de herramienta sin modificar el código de instrumentación.

Logging estructurado

Por qué logs estructurados

Los logs en texto plano son difíciles de buscar y correlacionar:

2024-01-15 10:30:00 INFO Order created successfully for customer 789

Los logs estructurados en JSON permiten búsquedas precisas:

{
  "timestamp": "2024-01-15T10:30:00Z",
  "level": "INFO",
  "service": "ms-orders",
  "correlationId": "abc-123",
  "traceId": "trace-456",
  "spanId": "span-789",
  "message": "Order created successfully",
  "context": {
    "orderId": "order-456",
    "customerId": "cust-789",
    "totalAmount": 150.00
  }
}

Campos estándar en cada log

Todos los servicios deben incluir estos campos en cada entrada de log:

CampoDescripción
timestampMomento exacto (ISO 8601 con timezone)
levelSeveridad (DEBUG, INFO, WARN, ERROR)
serviceNombre del servicio que genera el log
correlationIdID de correlación de la operación
traceIdID del trace distribuido
spanIdID del span actual
messageDescripción legible del evento
contextDatos adicionales relevantes

Centralización de logs

En un sistema distribuido, los logs de cada servicio deben enviarse a un sistema centralizado donde se puedan buscar y correlacionar:

graph LR
    MS1[ms-orders] --> AGG[Log Aggregator]
    MS2[ms-inventory] --> AGG
    MS3[ms-payments] --> AGG
    BFF[BFF] --> AGG
    AGG --> STORE[Elasticsearch / CloudWatch / Loki]
    STORE --> UI[Kibana / Grafana]

Trazabilidad en flujos asíncronos

La trazabilidad en flujos asíncronos es más compleja porque no hay una conexión HTTP directa entre el publicador y el consumidor del evento.

Propagación por eventos

El correlation ID y el trace ID deben incluirse en el payload del evento:

{
  "type": "OrderPlaced",
  "metadata": {
    "correlationId": "abc-123",
    "traceId": "trace-456",
    "parentSpanId": "span-789",
    "timestamp": "2024-01-15T10:30:00Z",
    "source": "ms-orders"
  },
  "payload": { ... }
}

Cuando el consumidor procesa el evento, crea un nuevo span hijo del span original, manteniendo la cadena de trazabilidad.

Desafío: latencia entre publicación y consumo

En flujos asíncronos, puede pasar tiempo entre la publicación y el consumo. El trace puede mostrar un gap temporal que es normal y esperado.

Diagnóstico de problemas con trazabilidad

Escenario: el usuario reporta que su orden no se confirmó

  1. Obtener el correlation ID de la orden (desde el frontend o los logs del BFF)
  2. Buscar todos los logs con ese correlation ID
  3. Visualizar el trace distribuido
  4. Identificar dónde se detuvo el flujo:
    • ¿El evento OrderPlaced se publicó?
    • ¿El servicio de inventario lo recibió?
    • ¿Hubo un error en el procesamiento?
    • ¿El evento de respuesta se publicó?

Sin trazabilidad, este diagnóstico requeriría revisar logs de cada servicio manualmente, buscando por timestamp y esperando encontrar algo relevante.

Resumen

La trazabilidad es lo que hace que un sistema distribuido sea operable. El correlation ID conecta todas las operaciones de un flujo, el tracing distribuido muestra la estructura temporal y las dependencias, y el logging estructurado permite buscar y correlacionar de forma eficiente. Sin estos tres pilares, diagnosticar problemas en producción se vuelve una tarea casi imposible.