ZI

Zipkin

Distributed tracing system for latency troubleshooting

Monitoring & Status ★ 17.5k stars Medium setup Apache-2.0

Zipkin is a distributed tracing system that gathers timing data needed to troubleshoot latency problems in service architectures. It collects, stores, and visualizes spans across requests.

Key features

  • Span collection and storage
  • Latency visualization
  • Dependency diagrams
  • Multiple storage backends

Pros & cons

Strengths

  • Simple to run
  • Long-established project

Trade-offs

  • Tracing only
  • Less active than Jaeger

Zipkin replaces

Last reviewed Aug 26, 2026 · 684 words

docker run -d --name zipkin -p 9411:9411 openzipkin/zipkin

That is a working distributed tracing backend. Open http://localhost:9411/zipkin, point an OpenTelemetry SDK at http://localhost:9411/api/v2/spans, and the first request through your services draws a waterfall of spans with per-hop timings. Nothing else in self-hosted observability reaches a useful screen this fast. What the command does not say is that every trace lives in the container's memory and disappears on restart, which is fine for an afternoon of debugging and wrong for anything you intend to keep.

The default store forgets everything, and caps what it remembers

Zipkin starts with STORAGE_TYPE=mem. Beyond vanishing on restart, the in-memory store holds a bounded number of spans, so a chatty service pushes older traces out within minutes. The persistent backends are Cassandra, Elasticsearch and MySQL. For a homelab the practical choice is Elasticsearch, with the caveat that Elasticsearch wants 1 to 2 GB of heap on its own, several times Zipkin's 512 MB floor. MySQL is the lightest option but the project steers you away from it for anything beyond low volume; Cassandra is the original backend and overkill below production scale.

services:
  elasticsearch:
    image: elasticsearch:8.14.3
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    volumes:
      - ./es-data:/usr/share/elasticsearch/data
  zipkin:
    image: openzipkin/zipkin
    environment:
      - STORAGE_TYPE=elasticsearch
      - ES_HOSTS=http://elasticsearch:9200
    ports:
      - "9411:9411"
    depends_on:
      - elasticsearch

One trap follows from persistence: the dependency diagram is computed live only for the in-memory store. With Elasticsearch or Cassandra you must run the separate openzipkin/zipkin-dependencies job on a schedule, or the diagram stays empty and you will assume something is broken.

Instrument with OpenTelemetry, not Zipkin's own libraries

Zipkin predates OpenTelemetry and still has its own instrumentation, Brave for Java above all. Do not start there. Every OpenTelemetry SDK ships a Zipkin exporter, and the OpenTelemetry Collector has one too, so the durable pattern is app to OTLP, collector to Zipkin. The collector lets you switch backends later by changing one exporter block, and it batches and retries so a Zipkin restart does not drop spans in flight. Two propagation formats exist, Zipkin's B3 headers and W3C traceparent; OpenTelemetry defaults to W3C, Zipkin does not care which arrives, but every service in a chain must agree or traces split in half.

Zipkin against Jaeger and Tempo

ZipkinJaegerTempo
Smallest deployment1 container1 container (all-in-one)1 container plus Grafana
UIBuilt in, basicBuilt in, better searchGrafana Explore
Persistent storageElasticsearch, Cassandra, MySQLElasticsearch, Cassandra, BadgerLocal disk or object storage
Accepts Zipkin formatYesYes, on 9411Yes
Project momentumStable, slowerActiveActive, Grafana-led

Jaeger accepts Zipkin-format spans on the same port, which makes switching cheap. Tempo stores traces on plain disk without a database, which is the biggest practical advantage for a small box, but it has no UI of its own. Zipkin's edge is being the simplest complete thing: one process, a UI, and 9 years of libraries that already speak its format.

What tracing will not tell you

Zipkin is tracing only. It has no metrics, no logs, no alerting, and no way to say "p95 latency rose 40% this week" without exporting to something else. A trace answers "where did these 800 ms go in this one request". Pair it with Prometheus-style metrics for trends and a log store for detail, and for LLM applications the observability and tracing piece covers why spans matter more there than anywhere.

What I'd do

For debugging, the one-line in-memory container, deleted when done. For keeping traces, pick by what you already run: Grafana on the box means Tempo; no Grafana and a wish for the simplest standalone UI means Zipkin on Elasticsearch with the dependencies job on a nightly cron. Instrument everything through the OpenTelemetry Collector regardless, so the backend decision stays reversible in one config block.

Compare Zipkin

4 head-to-head comparisons.

Similar monitoring & status apps