Grafana Tempo — Distributed Tracing
Grafana Tempo je open-source backend pre distribuovaný tracing, ktorý sa zameriava na jediný cieľ: ukladať a slúžiť 100 % traces za zlomok ceny iných riešení. Dosahuje to rovnakou filozofiou ako Loki — neindexuje obsah, ukladá traces komprimované do objektového storage (S3, GCS, Azure Blob) a indexuje iba trace_id.
Tempo tvorí tretí pilier Grafana LGTM stacku (Loki pre logs, Grafana pre vizualizáciu, Tempo pre traces, Mimir pre metrics).
Prečo distribuované tracing?
V monolite vám stačí stack trace. V mikroservisovej architektúre jedna HTTP requesta prechádza cez 5-10 služieb, každá volá DB, cache, externú API. Keď niečo zlyhá alebo spomalí, z logov nezistíte, kde je problém — logy sú samostatné riadky v samostatných službách.
Distribuovaný tracing sleduje request naprieč službami ako strom spánov (spans):
Trace: GET /checkout (850ms)
├── span: api-gateway (30ms)
├── span: auth-service (45ms)
│ └── span: redis.get (2ms)
├── span: cart-service (120ms)
│ ├── span: postgres.SELECT (80ms)
│ └── span: redis.get (5ms)
└── span: payment-service (650ms) ← bottleneck!
├── span: stripe.charge (580ms)
└── span: postgres.INSERT (40ms)
Okamžite vidíte, že 76 % času trávi čakaním na Stripe API. Bez tracingu by ste debugovali hodiny.
Tempo vs Jaeger vs Zipkin
| Aspekt | Jaeger | Zipkin | Tempo |
|---|---|---|---|
| Storage | Cassandra, Elastic, Badger | MySQL, Cassandra, Elastic | S3, GCS, Azure, local |
| Indexovanie | Trace search (full index) | Trace search | Len trace_id + TraceQL |
| Sampling potrebný | Áno (head sampling) | Áno | Nie — 100 % traces možné |
| Cena/TB | Vysoká (DB) | Vysoká (DB) | Nízka (object storage) |
| Query UI | Natívne | Natívne | Cez Grafana |
| Protokoly | OTLP, Jaeger, Zipkin | Zipkin | OTLP, Jaeger, Zipkin |
Najväčšia výhoda Tempa: nemusíte znižovať sampling rate na 1 % z obáv o cenu. Môžete ukladať 100 % traces a problémy nájdete aj tie, ktoré sa dejú raz za deň.
Kompromis: full-text vyhľadávanie naprieč všetkými traces je v Tempe obmedzené (TraceQL funguje, ale nie je to Elastic). Ak poznáte trace_id (napr. z logu cez TraceID label v Loki), Tempo je neporaziteľné. Ak chcete nájsť všetky traces, kde sa stalo X, TraceQL si poradí, ale pomalšie než Jaeger s full indexom.
Architektúra Tempo
OTel Collector / Agent
│ OTLP/gRPC
▼
┌──────────────┐
│ Distributor │ validate, shard by trace_id
└──────┬───────┘
▼
┌──────────────┐
│ Ingester │ in-memory → compacted blocks → S3
└──────┬───────┘
▼
┌──────────────┐
│ Object Store │ (S3, GCS, Azure, filesystem)
└──────┬───────┘
▲
┌──────────────┐
│ Querier │ reads blocks + ingesters
└──────┬───────┘
▼
┌──────────────┐
│ Query Front. │ splits queries, caches results
└──────────────┘
- Distributor — prijíma spany, validuje, shard-uje podľa
trace_id. - Ingester — agreguje spany do trace, drží v pamäti, pravidelne flushuje ako komprimovaný block.
- Compactor — merguje malé blocks do väčších, aplikuje retention.
- Querier — obsluhuje HTTP endpoint pre trace fetch a TraceQL search.
- Metrics generator (voliteľné) — generuje service graph a RED metriky z traces do Prometheu.
TraceQL — query language
TraceQL (od Tempo 2.0+) je jazyk na vyhľadávanie trace-ov:
# Všetky traces, kde bola HTTP status 500
{ status = error }
# Traces v service "checkout" s duration > 1s
{ resource.service.name = "checkout" && duration > 1s }
# Traces obsahujúce span, kde Stripe volal longer than 500ms
{ name = "stripe.charge" && duration > 500ms }
# Kombinácia
{ resource.service.name = "api" } >> { resource.service.name = "payment" && duration > 1s }
Operátor >> znamená "descendant span". Query sa vyhodnocuje nad blocks v object storage — pre dlhé obdobia je pomalšie než Jaeger, pre krátke (posledné hodiny) rýchle.
OpenTelemetry → Tempo integrácia
Tempo prijíma traces cez OTLP (OpenTelemetry protocol), nie je viazané na konkrétny SDK. Typický pipeline:
App (otel-sdk) ──► OTel Collector ──► Tempo
Tempo config (minimálny)
server:
http_listen_port: 3200
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
ingester:
trace_idle_period: 10s
max_block_duration: 5m
compactor:
compaction:
block_retention: 336h # 14 dni
storage:
trace:
backend: s3
s3:
bucket: tempo-traces
endpoint: s3.eu-central-1.amazonaws.com
region: eu-central-1
Aplikačná inštrumentácia (Python OTel SDK)
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
provider = TracerProvider()
provider.add_span_processor(
BatchSpanProcessor(
OTLPSpanExporter(endpoint="http://tempo:4317", insecure=True)
)
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
@app.route("/checkout")
def checkout():
with tracer.start_as_current_span("checkout") as span:
span.set_attribute("user_id", request.user.id)
charge_card()
write_order()
return "ok"
Request → spans → OTel SDK → Tempo → Grafana dashboard.
Prepojenie traces ↔ logs ↔ metrics v Grafana
Toto je killer-feature celého LGTM stacku. V Grafana data sources:
- Loki → Tempo: nastavíte
derivedFieldsv Loki data source tak, že každý log sotrace_id=abc123vygeneruje klikateľný odkaz, ktorý vás v Tempo otvorí presne na tom trace. - Tempo → Loki: v Tempo data source nastavíte "Trace to logs", čo v trace view zobrazí tlačidlo "View logs for this span". Otvorí Loki s filtrom
{pod="X"} |= "trace_id=abc123". - Tempo → Metrics: Service Graph panel v Grafana vizualizuje hovory medzi službami s RED metrikami (Rate, Errors, Duration), ktoré Tempo metrics_generator zapíše do Mimir/Prometheus.
Výsledok: z alertu (metrika) → trace (prečo) → log (detail) za 3 kliknutia.
Sampling stratégie
Aj keď Tempo dokáže ukladať 100 % traces, pri extrémnych objemoch (> 100k spans/sec) budete chcieť sampling:
Head sampling
Rozhoduje sa na začiatku (SDK). Jednoduché, lacné, ale stratíte pomalé request, ak sa na ne nenarazilo.
Tail sampling
Rozhoduje sa po zozbieraní celého trace. OTel Collector má tail_sampling processor:
processors:
tail_sampling:
policies:
- name: errors
type: status_code
status_code: { status_codes: [ERROR] }
- name: slow
type: latency
latency: { threshold_ms: 1000 }
- name: random
type: probabilistic
probabilistic: { sampling_percentage: 5 }
Týmto spôsobom ukladáte 100 % chýb a pomalých requestov, ale iba 5 % zvyšku.
Produkčné tipy
- Block retention — default 14 dní je rozumný kompromis medzi históriou a nákladmi.
- Search limits — TraceQL nad dlhým oknom (týždne+) je pomalé, preto nastavte
max_search_duration. - Compactor — musí bežať, inak sa z ingester blocks nikdy neflušne do konsolidovaných blockov.
- Multi-tenancy —
X-Scope-OrgIDheader, rovnako ako Loki a Mimir. - Trace → metrics — zapnite
metrics_generatora dostanete service graph zadarmo. - Retention warning — object storage je lacné, ale stovky TB traces vám tiež zaplnia S3. Nastavte lifecycle rules.
Zhrnutie
Tempo prináša distribuovaný tracing do éry, kde je cena za GB rozhodujúca. Ak používate Grafana, Prometheus a Loki, Tempo je logický doplnok — tým istým spôsobom uvažovania (labels, LogQL/TraceQL, object storage) a tým istým UI. Pre tímy, ktoré zvažujú Jaeger, je hlavná otázka: "Chceme 100 % traces za lacný peniaz alebo full-text search za drahý?" Tempo je odpoveď na prvú.
Spolu s OpenTelemetry (standard) a Grafana (UI) tvoria dnes triáda, ktorá definuje cloud-native observability.