1. Tempo 架构总览
1.1 Tempo 在 Grafana 可观测性栈中的角色
Grafana 可观测性栈由三大支柱构成:Metrics(指标)、Logs(日志)、Traces(链路)。Tempo 负责链路支柱,提供高性价比的分布式追踪存储与查询能力。
| 组件 | 职责 | 数据形态 |
|---|---|---|
| Mimir | 指标存储与查询 | Prometheus 指标 |
| Loki | 日志存储与查询 | 结构化/非结构化日志 |
| Tempo | 分布式追踪存储与查询 | Trace ID + Span 数据 |
| Grafana | 统一可视化面板 | 关联三大数据源 |
关键设计理念:Tempo 不依赖应用侧注入指标或日志索引,仅通过 Trace ID 即可关联 Metrics 与 Logs,实现真正的"零改造"可观测性关联。
1.2 核心组件介绍
Tempo 采用微服务架构,核心组件包括 Distributor、Ingester、Querier、Compactor,各组件职责明确、可独立扩缩容。
1.2.1 Distributor(分发器)
- 职责:接收来自应用 SDK 或 Agent 的 Span 数据(支持 OTLP、Jaeger、Zipkin 等协议),执行数据校验与 认证。
- 路由策略:根据 Trace ID 的 Hash 值将 Span 分发到对应的 Ingester 实例,保证同一 Trace 的所有 Span 进入同一 Ingester。
- 高可用:无状态设计,可水平扩展;前置负载均衡器(如 NGINX / Kubernetes Service)做流量分发。
1.2.2 Ingester(写入器)
- 职责:接收 Distributor 推送的 Span 数据,在内存中构建 Block(Tempo 的最小存储单元),定期 Flush 到后端存储。
- 生命周期:Block 经历 Receiving → Flushing → Complete 三个阶段,完成后不可变。
- 故障恢复:通过 WAL(Write-Ahead Log)保证数据不丢失,重启后从 WAL 恢复未 Flush 的 Block。
1.2.3 Querier(查询器)
- 职责:接收 Grafana 的 TraceQL 查询请求,从 Ingester(内存中的热数据)和后端存储(已 Flush 的冷数据)中检索匹配的 Trace。
- 索引加速:利用 Bloom Filter 和 Dedicated Column 快速定位目标 Block,避免全表扫描。
- 结果合并:将来自多个 Block 的 Span 按 Trace ID 合并为完整 Trace,返回给 Grafana。
1.2.4 Compactor(压缩器)
- 职责:将后端存储中的小 Block 合并为大 Block,减少文件数量、降低存储开销、提升查询效率。
- 触发策略:基于 Block 大小、时间窗口或 Compaction 周期自动触发。
- 副作用控制:合并过程中保留原始 Block 直到新 Block 写入完成,保证数据一致性。
1.3 数据流与工作流程
一条 Trace 从产生到可查询,经历以下完整生命周期:
- 数据产生:应用 SDK 生成 Span,通过 OTLP / Jaeger 协议发送至 Distributor。
- 数据分发:Distributor 校验数据合法性,按 Trace ID 取模 Hash 路由到对应 Ingester。
- 内存缓冲:Ingester 将 Span 追加到当前活跃 Block 的内存缓冲区,同时写入 WAL 确保持久性。
- Flush 落盘:Block 达到大小上限或时间阈值后,Ingester 将 Block 序列化并写入后端存储(如 S3、GCS、Azure Blob)。
- Compaction:Compactor 定期扫描小 Block,合并为大 Block,更新索引元数据。
- 查询响应:Querier 接收 Grafana 的 TraceQL 请求,并行检索 Ingester 内存 + 后端存储,合并结果返回。
值班台要点:当出现"Trace 查询超时"或"部分 Span 丢失"时,优先检查 Distributor 的请求成功率、Ingester 的 WAL 状态以及 Compactor 的合并队列深度。这三个组件是链路数据完整性的关键节点。
1.4 组件对比速查表
| 组件 | 状态 | 存储介质 | 扩缩容方式 | 关键指标 |
|---|---|---|---|---|
| Distributor | 无状态 | 无 | 水平扩展 | 接收速率、拒绝率 |
| Ingester | 有状态 | 内存 + WAL | 水平扩展(需 rebalance) | Block 数量、Flush 延迟 |
| Querier | 无状态 | 无 | 水平扩展 | P99 查询延迟、命中率 |
| Compactor | 无状态 | 无 | 水平扩展 | 合并队列长度、Block 大小 |
常见误区:Ingester 是有状态组件,直接重启可能导致未 Flush 的 Block 丢失。生产环境中务必配置 WAL 持久化,并采用滚动重启策略。