2. Tempo 架构概览:核心组件、数据流与角色职责
在深入存储调优之前,必须先理解 Tempo 的架构骨架。Tempo 采用微服务架构,核心组件各司其职,通过异步管道协同完成从数据接收到查询响应的全流程。本章将拆解每个组件的职责、数据流转路径以及它们在性能调优中的关键角色。
2.1 核心组件与角色职责
Tempo 由四个主要组件构成:Distributor、Ingester、Querier 和 Compactor。每个组件均可独立水平扩展,这也是 Tempo 能够支撑大规模分布式追踪场景的基础。
| 组件 | 核心职责 | 调优关注点 |
|---|---|---|
| Distributor | 接收 Trace 数据,进行校验、采样、负载均衡,并转发至 Ingester | 接收速率、gRPC 连接池、哈希一致性 |
| Ingester | 将 Trace 数据写入后端存储(如 S3/GCS),并维护内存中的最近数据索引 | 内存上限、Flush 策略、写入吞吐 |
| Querier | 接收查询请求,从 Ingester 内存和存储后端检索 Trace 数据 | 查询并发、缓存命中、索引扫描效率 |
| Compactor | 合并存储后端的小文件,减少碎片,优化查询扫描范围 | 合并周期、并行度、存储 IO 开销 |
调优视角: 在值班台场景中,Ingester 的内存配置和 Compactor 的合并策略直接影响查询延迟。如果 Ingester 频繁 OOM 或 Compactor 合并不及时,查询性能会急剧下降。
2.2 数据流全景:从接收到查询
一条 Trace 数据从被采集到最终可被查询,经历四个阶段。理解这个流程是定位性能瓶颈的前提。
- 接收与分发: 应用通过 OpenTelemetry SDK 或 Jaeger Agent 将 Trace 发送至 Distributor。Distributor 根据 TraceID 进行一致性哈希,将数据路由到对应的 Ingester 实例。
- 写入与缓冲: Ingester 将接收到的 Span 数据暂存于内存中,并定期 Flush 到后端存储(如对象存储或 Cassandra)。内存中的数据同时用于近期查询。
- 合并与优化: Compactor 异步扫描存储后端,将多个小文件合并为更大的块,减少存储碎片并优化索引结构。
- 查询与检索: Querier 接收用户查询,先向所有 Ingester 发起请求获取内存中的最新数据,再扫描存储后端中的历史数据,最终合并结果返回。
2.3 组件间通信与关键交互
组件之间的通信方式直接影响延迟和可靠性。Tempo 主要使用 gRPC 进行内部通信,并依赖一致性哈希实现数据路由。
- Distributor ↔ Ingester: 使用 gRPC 流式传输,Distributor 根据 TraceID 的哈希值将数据发送到对应的 Ingester 副本。此环节的瓶颈通常出现在 Distributor 的 gRPC 连接池大小和 Ingester 的接收队列深度。
- Ingester ↔ 存储后端: Ingester 将数据以 Parquet 格式写入对象存储(推荐)或 Cassandra。写入频率由
ingester.flush-check-period和ingester.trace-idle-period控制。 - Querier ↔ Ingester: 查询时,Querier 并行向所有 Ingester 发起 gRPC 请求,获取内存中的最新数据。如果 Ingester 响应慢,会直接拖累查询 P99 延迟。
- Compactor ↔ 存储后端: Compactor 定期扫描存储桶中的小文件,合并后重新写入。合并后的块越大,Querier 扫描时的索引效率越高。
性能调优提示: 在值班台场景中,如果发现查询延迟波动大,优先检查 Ingester 的内存使用率 和 Compactor 的合并进度。Ingester 内存过高会导致 GC 停顿,Compactor 落后会导致存储碎片化。
2.4 数据模型与存储结构
Tempo 将 Trace 数据组织为 Block 和 Index 两层结构。理解这一模型是调优存储性能的前提。
| 概念 | 说明 | 调优影响 |
|---|---|---|
| Block | 包含多个 Trace 的 Span 数据,以 Parquet 列式格式存储 | Block 大小影响 Compactor 合并效率与 Querier 扫描范围 |
| Index | 记录 Block 中 TraceID 的偏移量,用于快速定位 | 索引粒度越细,查询越快,但索引文件越大 |
| Tenant | 多租户隔离,每个租户拥有独立的 Block 和 Index 空间 | 租户数量影响存储布局和查询路由 |
2.5 关键配置参数速查
以下参数是值班台调优中最常触及的配置项,直接影响组件行为。
| 组件 | 参数 | 默认值 | 调优建议 |
|---|---|---|---|
| Distributor | distributor.receiver.max-recv-msg-size |
16 MB | 大 Trace 场景可提升至 64 MB |
| Ingester | ingester.max-block-duration |
30m | 降低至 10m 可减少内存压力,但增加存储碎片 |
| Ingester | ingester.trace-idle-period |
10s | 短 Trace 场景可降至 5s,加速 Flush |
| Compactor | compactor.compaction-interval |
30m | 高写入场景缩短至 15m,减少碎片窗口 |
| Querier | querier.max-concurrent-queries |
20 | 根据 CPU 核数调整,通常设为 2×CPU 核数 |
避坑提醒: 不要盲目调小
ingester.max-block-duration。虽然能降低内存占用,但会导致 Compactor 合并大量小文件,反而增加存储 IO 和查询延迟。建议结合写入速率和存储类型(SSD vs 对象存储)综合评估。
2.6 值班台实战视角:组件健康检查清单
在值班台日常巡检中,建议关注以下指标,快速定位组件级问题。
- Distributor: 检查
tempo_distributor_bytes_received_total是否平稳,如果出现陡降,可能是上游 SDK 或网络问题。 - Ingester: 监控
tempo_ingester_live_traces和process_resident_memory_bytes。如果内存持续增长且不回落,说明 Flush 阻塞。 - Compactor: 观察
tempo_compactor_blocks_combined_total和tempo_compactor_errors_total。错误数突增通常意味着存储后端限流或权限问题。 - Querier: 关注
tempo_querier_query_duration_seconds的 P99 值。如果超过 5 秒,优先排查 Ingester 响应时间和存储索引效率。
总结: Tempo 的架构设计决定了调优的杠杆点。Distributor 负责入口流量控制,Ingester 是内存与写入的平衡点,Compactor 影响存储布局,Querier 是查询性能的最终体现。掌握每个组件的角色和数据流,才能在值班台场景中快速定位瓶颈。