TempoGrafana Tempo)是 Grafana 生态中的链路追踪后端,用来接收、存储、查询和关联一次请求跨多个服务产生的 trace 数据。

它关注的问题不是“某个指标是多少”,也不是“某行日志写了什么”,而是一次请求经过哪些组件、每段耗时多少、错误出现在哪个 span 上。

核心问题

分布式系统里,一次用户请求可能经过网关、认证服务、业务服务、消息队列、数据库和第三方 API。只看单个服务的日志,很难回答:

  • 请求总耗时由哪一段贡献最多?
  • 错误是入口服务产生的,还是下游依赖传播上来的?
  • 失败请求和成功请求的调用路径有什么差别?
  • 某个 Mimir 指标异常时,能否找到对应的慢请求样本?

Tempo 解决的是 trace 的集中接收、长期保存和查询问题。它通常和 GrafanaLokiPrometheusMimir 配合使用,让 trace 可以和日志、指标互相跳转。

核心对象

对象含义工程关注点
Trace一次完整请求或业务流程的调用树trace_id 是否贯穿所有服务
Spantrace 中的一个操作片段,例如一次 HTTP 调用或数据库查询开始时间、结束时间、状态码、属性
Trace ID标识整条 trace 的 ID要写入日志或作为 exemplar,方便跳转
Span ID标识单个 span 的 ID用于表达父子关系和调用树
DistributorTempo 接收写入的入口组件协议、限流、租户、trace ID 分片
Live-store服务最近写入、还没完全落到长期存储的数据查询新 trace 时的可见性
Block-builder把 span 组织成块并写入长期存储block 大小、flush 周期、失败重试
Query frontend / Querier接收查询、切分任务、读取近期和历史数据查询延迟、并行度、缓存
Metrics-generator从 span 派生指标的可选组件生成 RED 指标、service graph 或 span metrics

这里的 trace_id 不是用户 ID,也不是一次 HTTP 连接 ID。它是一次逻辑请求链路的关联键,必须通过 trace context 在服务之间传播。span_id 只标识链路中的一个节点,不能单独代表完整请求。

核心机制

1. 应用先产生 trace

应用通过 OpenTelemetry SDK、框架 instrumentation 或其他 tracing 协议产生 span。典型数据流是:

service A
  -> creates root span with trace_id
  -> calls service B with trace context
service B
  -> creates child span
  -> exports spans through OTLP / Jaeger / Zipkin
collector or agent
  -> forwards spans to Tempo

如果服务之间没有传播 trace context,下游服务会生成新的 trace,Grafana 中看到的就是断裂的调用链。

2. Tempo 接收并组织 span

Tempo 的写入入口接收 OTLP 或其他 tracing 协议请求,校验租户、限流和格式后,按 trace_id 把 span 分发到后续组件。按 trace_id 分片的目标是让同一条 trace 的 span 尽量被组织到可查询的结构里。

在较新的分布式架构中,Tempo 可以用 Kafka 兼容队列作为持久中间层,然后由 block-builder 消费 span、构建列式 block 并写入对象存储;在单体模式中,数据路径更短,组件在同一进程内协作。无论哪种模式,查询都需要同时考虑近期数据和已经写入长期存储的数据。

3. 查询路径组合近期和历史数据

查询时,Grafana 或 API 先把查询发给 Tempo 的查询入口:

Grafana / API
  -> query frontend
  -> queriers
  -> live-store for recent traces
  -> object storage for historical traces
  -> merged result

近期 trace 通常还在 live-store 中,历史 trace 则在对象存储的 block 中。查询前端会把查询拆成多个并行任务,querier 从不同位置读取数据再合并结果。

4. Tempo 通过上下文和其他信号关联

Tempo 本身保存的是 trace 数据,但它和其他信号的关联依赖共同字段:

  • 日志里写入 trace_id,Grafana 就可以从 Loki 日志跳到 Tempo trace。
  • 指标样本带 exemplar,Grafana 就可以从 PrometheusMimir 指标点跳到 trace。
  • span 属性包含 service.name、HTTP route、status code 等信息,Grafana 就可以按服务、接口和错误状态筛选。

因此 Tempo 的可用性不仅取决于后端部署,还取决于应用 instrumentation 的质量。

工程用途

  • 慢请求定位:看一次请求的 waterfall,区分 CPU、数据库、RPC、队列等待和外部依赖耗时。
  • 错误传播分析:判断错误最早在哪个 span 出现,后续服务只是被动返回失败还是主动产生新错误。
  • 服务拓扑观察:从 span 的父子关系和 service name 推导服务调用关系。
  • 指标下钻:从错误率或延迟指标跳到具体 trace 样本,而不是只看聚合趋势。
  • 日志关联:用 trace ID 把同一次请求的跨服务日志串起来。

常见观察指标包括 span ingest rate、dropped spans、query latency、object storage error、live-store 可用窗口、trace 搜索命中率和 metrics-generator 生成的 RED 指标。

边界与常见坑

  • Tempo 不是 tracing SDK:它接收和查询 trace;应用侧仍需要 OpenTelemetry 或其他 instrumentation 产生 span。
  • 有 Tempo 不等于有完整链路:没有 trace context 传播、采样配置过强或某些服务没接入时,trace 会断裂或缺段。
  • trace 成功写入不等于立刻可查到全部历史:近期数据、block flush、对象存储和查询索引之间有时间窗口。
  • 采样策略会改变事实可见性:被采样丢弃的请求不会出现在 Tempo 中,排障时要结合指标和日志判断总体影响。
  • 属性不是越多越好:把请求体、用户隐私、完整 URL 或高基数字段放入 span 属性,会带来成本、隐私和查询问题。
  • Tempo 不替代日志和指标:trace 适合解释路径和局部耗时;趋势、容量和阈值仍应由 指标 承担,事件细节仍应由日志补足。

相关术语

外部参考