3. Tempo 架构概览:核心组件、数据流与存储设计
要理解 Tempo 的检索优化策略,首先需要掌握其整体架构。Tempo 采用微服务架构,将数据接收、处理、存储与查询职责解耦。本章将深入剖析其核心组件、数据流转路径以及底层存储设计,为后续的检索加速与 MTTR 复盘奠定基础。
3.1 核心组件与职责
Tempo 由四个主要组件构成,每个组件承担特定的职责,协同完成 Trace 数据的全生命周期管理。
| 组件 | 核心职责 | 关键特性 |
|---|---|---|
| Distributor | 接收并验证 Trace 数据,进行负载均衡与数据分片 | 无状态、可水平扩展、支持多种协议(Jaeger、Zipkin、OTLP) |
| Ingester | 将 Trace 数据写入后端存储,构建内存中的 Block 索引 | 有状态、负责数据持久化、管理 Block 生命周期 |
| Querier | 接收查询请求,从 Ingester 和存储后端检索 Trace 数据 | 无状态、支持 TraceQL 查询语言、实现数据合并与去重 |
| Compactor | 合并小 Block 为大 Block,优化存储效率与查询性能 | 后台异步运行、减少存储碎片、提升扫描效率 |
架构设计要点: Distributor 和 Querier 是无状态组件,便于弹性伸缩;Ingester 是有状态组件,需要关注其数据持久化与故障恢复策略。Compactor 作为后台任务,对实时写入无影响,但对长期存储和查询性能至关重要。
3.2 数据流与处理流程
一条 Trace 数据从被采集到最终可被查询,经历了完整的流水线处理。下图展示了 Tempo 的核心数据流。
3.3 存储设计:Block 与 Backend
Tempo 的存储设计围绕 Block 这一核心概念展开。每个 Block 包含一段连续时间窗口内的 Trace 数据,并附带索引和元数据。
3.3.1 Block 结构
一个 Block 由以下部分组成:
- Data 文件:存储序列化后的 Span 数据,采用 Parquet 或 Protobuf 格式。
- Index 文件:包含 Trace ID 到数据位置的映射,用于快速定位。
- Meta 文件:记录 Block 的元信息,如时间范围、Span 数量、大小等。
3.3.2 存储后端支持
Tempo 支持多种后端存储,以适应不同的部署规模和成本要求。
| 存储后端 | 适用场景 | 性能特点 |
|---|---|---|
| S3 / GCS / Azure Blob | 生产环境、大规模部署 | 高吞吐、低成本、支持对象存储 |
| MinIO | 本地开发、测试环境 | 兼容 S3 API、易于部署 |
| Local Filesystem | 单机测试、小规模验证 | 简单直接、无网络开销 |
3.4 数据生命周期与 Compaction
Compactor 是 Tempo 存储优化的关键组件。它定期扫描存储后端中的小 Block,将其合并为更大的 Block,从而减少文件数量、降低查询时的扫描开销。
Compaction 核心流程:
- 扫描:Compactor 列出存储后端中所有未合并的 Block。
- 分组:根据时间范围和租户 ID 将小 Block 分组。
- 合并:读取组内所有 Block 的数据,合并排序后写入新的大 Block。
- 清理:删除原始的小 Block,更新元数据。
Compaction 策略可以通过参数调整,例如合并后的目标 Block 大小、合并频率等,以平衡存储成本和查询性能。
3.5 检索路径与优化基础
理解 Tempo 的检索路径是优化查询性能的前提。一次典型的 Trace 查询流程如下:
- 步骤 1:Querier 接收 TraceQL 查询请求,解析查询条件。
- 步骤 2:Querier 并行向所有 Ingester 发送查询,获取内存中的实时数据。
- 步骤 3:Querier 根据查询时间范围,向存储后端发起 Block 扫描请求。
- 步骤 4:Querier 合并来自 Ingester 和存储后端的结果,去重后返回给客户端。
性能瓶颈提示: 在未优化的情况下,查询性能主要受限于 Block 扫描效率。过多的未合并小 Block 会导致大量文件 I/O 操作,显著增加查询延迟。Compactor 的合理配置和存储后端的 IOPS 能力是检索优化的关键基础。