10. Storage backends

Por: Artiko
jaegerstoragecassandraelasticsearchclickhousebadger

10. Storage backends

Jaeger no almacena por sí mismo: delega en un backend externo. La decisión de qué backend usar es estratégica: condiciona costos, ops, performance de búsqueda y retención.


Comparación rápida

BackendPersistenciaEscalaBúsqueda ricaCostoOps
memoryNoSingle nodeBásica00
badgerSí (disco local)Single nodeBásicaBajoMínima
cassandraSí (cluster)HorizontalLimitadaAltoAlta
elasticsearch / opensearchSí (cluster)HorizontalRicaAltoMedia-alta
clickhouse (v2)Sí (cluster o single)HorizontalRicaMedioMedia

Memory

Default del all-in-one. Ya lo vimos en el capítulo 3.

docker run -e SPAN_STORAGE_TYPE=memory \
  -e MEMORY_MAX_TRACES=100000 \
  jaegertracing/all-in-one:1.62

Badger (LSM tree embebido)

Embebido en el binario, persiste a disco local. Ideal para entornos chicos donde no querés operar Cassandra/ES.

docker run -d --name jaeger \
  -e SPAN_STORAGE_TYPE=badger \
  -e BADGER_EPHEMERAL=false \
  -e BADGER_DIRECTORY_VALUE=/badger/data \
  -e BADGER_DIRECTORY_KEY=/badger/key \
  -v jaeger-badger:/badger \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 16686:16686 -p 4317:4317 \
  jaegertracing/all-in-one:1.62

Cuándo usar Badger

Cuándo NO usar Badger

Retención

-e BADGER_SPAN_STORE_TTL=72h0m0s

72 horas por default. Después de ese tiempo, las trazas se borran.


Cassandra

El backend “histórico” de Jaeger. Diseñado para volumen alto.

Setup mínimo con docker-compose

services:
  cassandra:
    image: cassandra:4.1
    environment:
      MAX_HEAP_SIZE: "1G"
      HEAP_NEWSIZE: "256M"
    volumes:
      - cassandra-data:/var/lib/cassandra

  jaeger-init:
    image: jaegertracing/jaeger-cassandra-schema:1.62
    environment:
      MODE: "test"
      DATACENTER: "dc1"
      KEYSPACE: "jaeger_v1_dc1"
      CASSANDRA_PROTOCOL_VERSION: "4"
    depends_on: [cassandra]

  jaeger-collector:
    image: jaegertracing/jaeger-collector:1.62
    environment:
      SPAN_STORAGE_TYPE: cassandra
      CASSANDRA_SERVERS: "cassandra"
      CASSANDRA_KEYSPACE: "jaeger_v1_dc1"
    ports:
      - "4317:4317"
      - "4318:4318"
    depends_on: [jaeger-init]

  jaeger-query:
    image: jaegertracing/jaeger-query:1.62
    environment:
      SPAN_STORAGE_TYPE: cassandra
      CASSANDRA_SERVERS: "cassandra"
      CASSANDRA_KEYSPACE: "jaeger_v1_dc1"
    ports:
      - "16686:16686"
    depends_on: [cassandra]

volumes:
  cassandra-data:

Retención (TTL)

Cassandra implementa retención con TTL nativo de la base, configurado en el schema:

docker run --rm jaegertracing/jaeger-cassandra-schema \
  MODE=prod \
  DATACENTER=dc1 \
  KEYSPACE=jaeger_v1_dc1 \
  TRACE_TTL=172800  # 2 días en segundos

Pros

Contras


Elasticsearch / OpenSearch

El segundo backend más usado, especialmente cuando ya tenés ES corriendo para logs.

Setup con docker-compose

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.4
    environment:
      discovery.type: "single-node"
      xpack.security.enabled: "false"
      ES_JAVA_OPTS: "-Xms2g -Xmx2g"
    ports:
      - "9200:9200"

  jaeger-collector:
    image: jaegertracing/jaeger-collector:1.62
    environment:
      SPAN_STORAGE_TYPE: elasticsearch
      ES_SERVER_URLS: "http://elasticsearch:9200"
      ES_NUM_SHARDS: "5"
      ES_NUM_REPLICAS: "1"
    ports:
      - "4317:4317"
    depends_on: [elasticsearch]

  jaeger-query:
    image: jaegertracing/jaeger-query:1.62
    environment:
      SPAN_STORAGE_TYPE: elasticsearch
      ES_SERVER_URLS: "http://elasticsearch:9200"
    ports:
      - "16686:16686"
    depends_on: [elasticsearch]

Pros

Contras

Retención (rollover de índices)

ES no tiene TTL por documento. La retención se hace por rollover de índices:

# Borrado simple con curl (script en cron)
INDEX_DATE=$(date -d '7 days ago' +%Y-%m-%d)
curl -X DELETE "http://elasticsearch:9200/jaeger-span-${INDEX_DATE}"
curl -X DELETE "http://elasticsearch:9200/jaeger-service-${INDEX_DATE}"

O configurás ILM (recomendado en producción).


ClickHouse (Jaeger v2)

Soporte oficial en Jaeger v2 (capítulo 11). Excelente ratio costo/performance.

Pros

Contras

ClickHouse ha pasado a ser una recomendación fuerte en deployments nuevos a partir de 2025.


Comparación de queries soportadas

OperaciónMemoryBadgerCassandraES/OSClickHouse
Lookup por trace_id
Filtro por service
Filtro por operation
Filtro por tag (k=v)parcial
Filtro por tag wildcard
Filtro por duration range
Búsqueda full-text en logs
Dependency graph en vivo❌ (batch)

Capacity planning rápido

Reglas del pulgar para dimensionar:

Ejemplo:

Multiplicá por días de retención y agregá margen para metadata, índices.


Decisión: árbol de bolsillo

flowchart TD
    Q1{Volumen?} -->|"Bajo / dev"| M[memory o badger]
    Q1 -->|"Medio"| Q2{Stack ya tiene ES?}
    Q1 -->|"Alto"| Q3{Búsqueda rica?}
    Q2 -->|"Sí"| ES[elasticsearch]
    Q2 -->|"No"| Q4{Greenfield?}
    Q4 -->|"Sí"| CH[clickhouse v2]
    Q4 -->|"No"| C[cassandra]
    Q3 -->|"Sí"| ES
    Q3 -->|"No, costo importa"| CH

¿Qué viene?

Tenés tracing operativo con storage real. Hora de hablar del futuro: en el próximo capítulo entramos en Jaeger v2, la versión basada en OpenTelemetry Collector que reemplaza la arquitectura clásica.