Grafana Tempo 架构深度解析:写入路径、Parquet 列式存储与 TraceQL 查询的组件体系

发布时间:2026/9/17 23:16:05

Grafana Tempo 架构深度解析:写入路径、Parquet 列式存储与 TraceQL 查询的组件体系 Grafana Tempo 架构深度解析写入路径、Parquet 列式存储与 TraceQL 查询的组件体系【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempoGrafana Tempo 是一个面向高吞吐、低依赖场景的分布式链路追踪后端。本文基于仓库中的 Tempo architecture 文档系统讲解 Tempo 如何完成接入链路数据 → 写入对象存储 → 按 TraceID 或 TraceQL 检索的全过程并结合源码剖析各组件职责、单体/微服务两种部署模式以及存储设计。读完本文你将掌握 Tempo 的写入与读取生命周期、每个组件的运行方式与适用模式以及如何通过-target参数组织实际部署。设计目标塑造 Tempo 架构的四个原则Tempo 的架构围绕以下四个目标展开它们直接决定了数据如何被接入、存放和查询低成本的存储所有链路trace数据全部存放在对象存储object storage中不依赖自建的高成本本地存储集群。读写独立伸缩在微服务模式下Tempo 将写入路径write path与读取路径read path彻底分离可分别按需扩缩容。无需额外复制的持久性微服务模式下一个 Kafka 兼容的消息队列充当写入预写日志write-ahead log, WAL。只要 Kafka 确认写入数据即视为持久化因此 Tempo 在写入路径上不做跨实例复制可以以复制因子 1RF1运行显著降低成本。高效的属性查询数据块以 Apache Parquet 列式格式存储查询时只读取所需列而非扫描整条 trace从而加速基于属性的搜索。这四个目标在源码中都有对应体现PushSpansToKafka、ConsumeFromKafka等开关决定了数据在进程间是走 Kafka 还是进程内直推见下文源码分析而 tempodb/encoding/vparquet5 目录则承载了 Parquet 编码的具体实现。部署模式一个二进制两种运行形态Tempo 的所有组件都被编译进同一个二进制文件通过-target参数命令行形式--target决定当前进程运行哪些组件。这带来了两种部署形态单体模式Monolithic-targetall默认值所有必需组件运行在单个进程中无需 Kafkadistributor 通过进程内调用把数据直接推送给 live-store 与 metrics-generator。微服务模式Microservices每个组件以独立进程、独立-target运行需要 Kafka 兼容系统是生产环境推荐模式。无论哪种模式生产环境都建议使用对象存储本地文件系统后端仅用于开发与测试。从 cmd/tempo/app/modules.go 可以看到这一设计的直接实现文件顶部定义了全部目标常量modules.go包括all、distributor、metrics-generator、querier、query-frontend、block-builder、backend-scheduler、backend-worker、live-store等模块管理器setupModuleManager随后注册了每个模块及其依赖关系SingleBinary目标的依赖列表把BackendScheduler、BackendWorker、QueryFrontend、Querier、Distributor、MetricsGenerator、LiveStore全部串起来modules.go对应一个进程跑所有组件的单体形态。-target的具体取值与说明汇总如下来源command-line-flags.mdTarget说明all单体模式单进程运行全部组件默认distributor接收并分发 trace 数据给下游组件metrics-generator从摄入的 trace 数据生成指标querier查询后端存储中的 trace 与指标query-frontend提供搜索 API并把查询拆分为并行任务block-builder从 Kafka 消费数据并写入后端存储块backend-scheduler在多个 worker 间调度、协调后端查询任务backend-worker执行 backend scheduler 分配的任务live-store消费 Kafka 中近期数据服务实时查询注意Tempo 3.0 移除了旧的ingester、compactor与scalable-single-binarySSB目标此前被称为 scalable monolithic mode 的形态已不再存在写入与压缩职责分别由 live-store、block-builder 和 backend scheduler/worker 接管。单体模式何时使用与注意事项单体模式适合快速上手、开发环境以及中低 trace 量的场景此时运维简单性优先于独立伸缩。它的局限在于所有组件共享同一资源池查询负载的突增会影响写入吞吐反之亦然随着数据量增大live-store 与 querier 等组件的内存压力集中在一台实例上可能引发 OOM。部署时需为实例预留足够内存以同时容纳 live-store 的内存 trace 缓冲、querier 的并发任务执行以及 backend worker 合并块时的内存开销。微服务模式独立伸缩与故障隔离微服务模式适用于生产环境、高 trace 量、对高可用有要求的场景。其优势包括block-builder、querier、live-store 等组件可独立扩缩容故障域相互隔离querier OOM 不影响数据接入block-builder 重启不影响查询可用性live-store 可跨可用区部署以提升高可用性每个组件按需分配资源避免单体模式的过度供给。各组件的扩展策略参考如下来源deployment-modes.md组件扩展策略说明Distributor水平无状态按摄入速率扩展Block-builder水平受 Kafka 分区数约束按数据量扩展Live-store水平受 Kafka 分区数约束按近期数据查询量与内存扩展Query frontend垂直保持 2 个副本优先提升 CPU/RAM 而非加副本Querier水平按查询并发与延迟要求扩展Backend worker水平处理压缩与保留按块数量与压缩滞后扩展Metrics-generator水平按 trace 量与生成的序列数量扩展在微服务模式中Kafka 是写入路径的主干通信通道distributor 写入 Kafkablock-builder、live-store、metrics-generator 各自独立消费querier 通过 gRPC 访问 live-store 获取近期数据所有组件则统一访问对象存储获取块数据。新增或下线任一组件实例都无需重配其他组件除 Kafka 分区管理外。从单体迁移到微服务时只需为各组件指定相应-target、让所有组件指向同一套 Kafka、对象存储与 memberlist然后缩容单体实例即可由于 Kafka 已保证持久性迁移过程不丢数据live-store 启动时从 Kafka 重放block-builder 从上次提交的偏移量继续消费。两种模式下的组件差异速查组件配置块单体模式微服务模式Distributordistributor进程内直推 live-store 与 metrics-generator写入 KafkaIngestingest不使用写入路径的 Kafka 连接设置Block-builderblock_builder不使用消费 Kafka构建 Parquet 块并刷入对象存储Live-storelive_store直接从 distributor 接收数据从 Kafka 消费Live-store clientlive_store_clientquerier 到 live-store 的客户端进程内querier 到 live-store 的 gRPC 客户端Query frontendquery_frontend进程内运行独立进程Querierquerier进程内运行独立进程Backend scheduler / workerbackend_scheduler/backend_worker进程内运行独立进程Metrics-generatormetrics_generator可选进程内运行可选独立进程Storagestoragetrace 数据存储后端trace 数据的对象存储数据流转写入路径与读取路径Tempo 将把数据写入存储的写入路径与服务查询的读取路径明确分离两条路径的生命周期如下。一条写入的生命周期以下步骤描述微服务模式的写入路径单体模式下distributor 以进程内方式把数据推给 live-store 与 metrics-generator而非写入 Kafka追踪管线如 OpenTelemetry Collector、Grafana Alloy把 trace 数据发送给distributor。distributor 校验请求按 trace ID 对 trace 分片并写入Kafka。Kafka 确认写入后distributor 向客户端返回响应。此后的下游消费都是异步的Live-store从 Kafka 消费数据使近期数据可被查询。Block-builder从 Kafka 消费数据为长期对象存储构建数据块。Metrics-generator可选从 Kafka 消费数据从 trace 派生指标。源码印证在 initDistributor 中t.cfg.Distributor.PushSpansToKafka !singleBinarymodules.go即只有非单体模式才写 Kafka单体模式下则注册两个进程内目标函数localPushTargets.Generator与localPushTargets.LiveStore把数据直接 push 给同进程的 metrics-generator 与 live-store。类似地initLiveStore 中t.cfg.LiveStore.ConsumeFromKafka !IsSingleBinary(t.cfg.Target)modules.go决定 live-store 是否从 Kafka 消费initGenerator 中ConsumeFromKafka同理控制 metrics-generator。一条读取的生命周期Query frontend接收查询将其拆分为近期数据与长期存储两类任务。Querier从live-store获取近期数据。对更早的数据querier 从对象存储拉取数据块。结果聚合后返回给用户。读取路径在模块依赖图中同样清晰Querier模块依赖{Common, Store, LiveStoreRing, PartitionRing}而QueryFrontend依赖{Common, Store, OverridesAPI}modules.goinitQuerier 还会在单体模式下自动把 worker 地址指向本进程 gRPC 端口modules.go保证单体部署开箱即用。组件总览组件职责使用模式Distributor接收并校验 span路由到写入路径两种模式Kafka 兼容队列distributor 与下游消费者之间的持久化 WAL微服务模式Block-builder构建 Apache Parquet 块并刷入对象存储微服务模式Live-store服务近期 trace 数据的查询两种模式Query frontend接收查询并拆分为并行任务两种模式Querier针对 live-store 与对象存储执行查询任务两种模式Backend scheduler 与 worker处理压缩、保留与块列表维护两种模式Metrics-generator可选从 trace 派生 RED 指标与服务图两种模式对象存储所有 trace 数据的长期存储两种模式组件详解Distributordistributor 是 trace 数据的入口。它接收 OTLP推荐、Jaeger 和 Zipkin 三种格式的 span并按照每租户的接入限制per-tenant ingestion limits进行校验。微服务模式下它按 trace ID 分片并写入 Kafka单体模式下则进程内推送给 live-store 与 metrics-generator。其实现位于 modules/distributor/distributor.go分片与转发逻辑可以追溯到PushSpansToKafka与LocalPushTargets的分支处理。Kafka 兼容队列微服务模式下Tempo 使用 Kafka 兼容系统如 Apache Kafka 或 WarpStream作为 distributor 与下游消费者之间的持久化 WAL。由于 Kafka 在确认写入后即保证持久性Tempo 可以以复制因子 1RF1运行无需在写入路径做额外复制。单体模式不使用 Kafka。Kafka 的接入配置在ingest配置块下可参考 configure-kafka 了解完整设置。Block-builderblock-builder 从 Kafka 消费 trace 数据把 span 组织成 Apache Parquet 数据块并刷入对象存储长期保留。它只在微服务模式运行单体模式下由 live-store 直接向对象存储刷块。对应实现见 modules/blockbuilder/blockbuilder.go其块配置与 WAL 版本始终取自storage.trace.block见 initBlockBuilder。Live-storelive-store 服务近期 trace 数据trace 保存在内存和本地 WAL 中因此在摄入后数秒内即可查询。微服务模式下它从 Kafka 消费数据单体模式下直接从 distributor 接收。为保障高可用live-store 可以跨可用区部署。实现位于 modules/livestore/live_store.go它对外以 gRPC 暴露 Querier 与 Metrics 服务modules.go。Query frontendquery frontend 是查询入口接收 TraceQL 查询与 trace ID 查询把每条查询拆分为并行任务分发给 querier再合并结果返回最终响应。它在 modules/frontend/frontend.go 中实现initQueryFrontend 为其注册了 trace by ID、search、search tags、metrics query、MCP 等一系列 HTTP 端点。Querierquerier 执行 query frontend 分发的任务从 live-store 获取近期数据从对象存储获取历史数据然后返回给 query frontend 合并。实现见 modules/querier/querier.go其注册的 HTTP 处理器覆盖 TraceByID、Search、SearchTags、SearchTagValues、QueryRange 等modules.go。Backend scheduler 与 workerbackend scheduler 与 backend worker 共同负责对象存储数据的压缩compaction、保留retention与块列表blocklist维护scheduler 创建任务并分派给 workerworker 把小块压缩成更大的块并按保留期过期数据。两者取代了旧版的 compactor。相关代码见 modules/backendscheduler/backendscheduler.go 与 modules/backendworker/backendworker.go。保留策略的具体过期逻辑可参考 tempodb/retention.go。Metrics-generatormetrics-generator 是可选组件它从 trace 派生速率rate、错误error、耗时duration指标与服务图service graphs并通过 remote write 写入 Prometheus 或 Grafana Mimir 等指标后端。实现位于 modules/generator/generator.go支持span-metrics、service-graphs等处理器。对象存储对象存储是所有 trace 数据的长期存储层。Tempo 支持三种主流对象存储 API并提供本地文件系统后端用于开发与测试Amazon S3以及 MinIO 等 S3 兼容系统Google Cloud StorageGCSMicrosoft Azure Blob Storage本地文件系统开发/测试各后端实现分别位于 tempodb/backend/s3、tempodb/backend/gcs、tempodb/backend/azure、tempodb/backend/local。后端 worker 在保留期过后使对象存储中的数据过期从而强制执行保留策略。存储Parquet 列式块与保留Tempo 把全部 trace 数据存放于对象存储以 Apache Parquet 列式格式组织成数据块。列式存储的关键收益是查询时只读取所需属性对应的列而不是扫描整条 trace。Tempo 当前的 Parquet 编码版本为 vParquet5实现位于 tempodb/encoding/vparquet5。保留策略通过 backend worker 在对象存储中过期数据实现。你能查询什么Tempo 回答两类读取请求按 trace ID 查询特定 trace以及使用 TraceQLTempo 的 trace 查询语言跨 trace 搜索。TraceQL 的解析器、AST 与执行引擎位于 pkg/traceql。此外你还可以直接基于 trace 数据计算 TraceQL 指标例如 span 速率与延迟分位数并使用可选的 metrics-generator 产出 RED 指标与服务图。接入方面Tempo 支持 OpenTelemetryOTLP、Jaeger 与 Zipkin 三种格式。同时 Tempo 是多租户的trace 数据在存储层按租户隔离。命令行与配置实操关键命令行标志Tempo 的全局与部署相关标志完整参考见 command-line-flags.mdFlag说明默认值--config.file要加载的配置文件--config.expand-env在配置文件中展开环境变量false--config.verify校验配置后退出false--target要运行的目标模块all--multitenancy.enabled启用多租户false--http-api-prefix所有 HTTP API 端点的字符串前缀--shutdown-delaySIGTERM 与关闭之间的等待时间0--log.level日志级别debug/info/warn/errorinfo--log.format日志格式logfmt/jsonlogfmt--server.http-listen-portHTTP 监听端口3200--server.grpc-listen-portgRPC 监听端口9095--health对/ready端点执行健康检查后退出false--health.url健康检查 URLhttp://localhost:3200/ready常见用法示例# 以配置文件启动默认单体模式 tempo --config.file/etc/tempo/config.yaml # 以指定目标启动微服务模式下的 distributor tempo --targetdistributor --config.file/etc/tempo/config.yaml # 只校验配置、不启动 tempo --config.file/etc/tempo/config.yaml --config.verify # 打印版本信息 tempo --version # 在配置文件中展开环境变量便于注入密钥与环境相关值 tempo --config.file/etc/tempo/config.yaml --config.expand-env # 微服务部署中为 distributor 指定自定义 HTTP 端口并以 JSON 格式输出日志 tempo --targetdistributor \ --config.file/etc/tempo/config.yaml \ --server.http-listen-port3200 \ --log.formatjson # 单体模式启用多租户并设置 30 秒优雅关闭延迟 tempo --config.file/etc/tempo/config.yaml \ --multitenancy.enabled \ --shutdown-delay30s--health标志专为无 shell 的 distroless 容器镜像设计由于镜像内没有curl/wget可直接用它编写 Dockerfile 健康检查HEALTHCHECK CMD [/tempo, --health]。Kubernetes 用户通常改用 httpGet 探针直接探测/ready端点。配置加载与单体模式默认行为从 cmd/tempo/main.go 的loadConfigmain.go可以看出配置加载顺序先解析命令行标志注册默认值再叠加配置文件YAML严格解析最后用 CLI 覆盖。有趣的是当目标为单体模式时代码会强制把 Generator、LiveStore 的 ring KVStore 设为inmemory、地址设为127.0.0.1并清空 BackendWorker 的 ring KVStore 以进入无分片模式main.go——这正是单体模式无需额外 KV 存储即可运行的原因。单二进制单体模式配置示例仓库中的 example/docker-compose/single-binary/tempo.yaml 是一个完整的单体模式示例默认-targetall故未显式写出 targetstream_over_http_enabled: true server: http_listen_port: 3200 log_level: info distributor: receivers: otlp: protocols: grpc: endpoint: tempo:4317 http: endpoint: tempo:4318 #log_received_spans: # enabled: true # log_discarded_spans: # enabled: true metrics_generator: registry: external_labels: source: tempo cluster: docker-compose storage: path: /var/tempo/generator/wal remote_write: - url: http://prometheus:9090/api/v1/write send_exemplars: true query_frontend: mcp_server: enabled: true storage: trace: backend: local wal: path: /var/tempo/wal # where to store the wal locally local: path: /var/tempo/blocks overrides: defaults: metrics_generator: processors: [span-metrics, service-graphs] generate_native_histograms: both usage_report: reporting_enabled: false该示例使用local本地文件系统后端适合开发/测试生产请改用对象存储配置了 OTLP gRPC/HTTP 接收器、metrics-generator 及其到 Prometheus 的 remote write、以及 query frontend 的 MCP server。微服务模式的完整多组件示例可参考仓库中的 example/docker-compose/distributed 目录。三条必须记住的事实关于 trace 数据有三点值得特别留意trace 没有结束概念一条 trace 可以从任何一个携带全新 trace ID 的 span 开始未来任意时刻都可能有新 span 追加进来。按 trace ID 查询返回的是完整关系图Tempo 返回当前已存储/接入的所有属于该 trace 的 span并以映射后的响应呈现即 span 之间的父子/兄弟关系图例如 Grafana 可以据此对 trace 做可视化渲染。TraceQL 查询不保证时间序返回的是所有匹配过滤条件的 trace但可能不是按时间顺序——因为某些 querier 返回结果比其他 querier 更快。当 TraceQL 查询达到最大 trace 数限制时query frontend 会先返回已收集到的 trace 与 span并停止等待尚未返回的 querier。下一步规划与部署 Tempo参见 set-up-for-tracing 下的部署文档。深入了解部署模式细节见 Deployment modes。学习 span 的组成部分与可查询字段见 Trace structure。掌握完整配置项见 configuration 文档。深入源码模块装配逻辑见 cmd/tempo/app/modules.go各组件实现位于 modules 目录Parquet 编码在 tempodb/encoding/vparquet5TraceQL 引擎在 pkg/traceql。【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/17 23:16:05

Sunshine 串流服务器:10 分钟配通 Moonlight

Sunshine 串流服务器:10 分钟配通 Moonlight 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 你窝在沙发里,想玩的那款 3A 装在书房那台电脑上,屏…

2026/9/17 23:11:04

从状态机到权限矩阵:用软件工程思维拆解合伙协议

简介:这是一份面向计划共同出资创办公司的创业者与合伙人团队的多方股份合作协议书范本,可帮助解决多人合伙时权责不清、出资比例与利润分配不明等核心问题。协议逐项列明合伙人身份确认、出资总额与股份占比、股利分配与保底收益、合伙期限、入股退股及…

2026/9/18 0:21:11

大数据+智慧戒毒所智能化监管方案:实时预警与数据底座设计

简介:这份《大数据智慧戒毒所智能化监管方案》以PDF形式提供,面向戒毒所信息化建设者、监管场所管理人员及智慧司法方案设计人员,聚焦如何用数据驱动提升监管效率、风险预警与康复管理水平。压缩包仅含1个PDF文件,约2.87MB&#x…

2026/9/18 0:21:11

豆包AI手机零售版实测:加价预装App,AI优化只是噱头?

我前两天去数码城陪朋友提手机,柜台角落摆着一台贴上“豆包 AI 手机零售版”标签的机器,标价比同配置普通版贵了整整八百块。导购说得很玄乎,内置豆包大模型,写文案、查资料、清垃圾、优化系统全是“一句话的事”。我当时没忍住&a…

2026/9/18 0:21:11

C++ 常用标准库函数实战避坑:string、vector、algorithm

简介:这是一份面向C初学者与需要随时查阅标准库接口的开发者整理的常用函数速查文档,针对日常编程中数学运算、字符串处理、内存操作与类型转换等高频需求,把零散的函数原型与返回值说明汇集到一处,便于快速定位与对照使用。压缩包…

2026/9/18 0:21:11

从BrandDynamics到有意义差异化:品牌资产量化与实力溢价归因

简介:这份PDF资料是KantarMillwardBrown(Millward Brown)关于「有意义、差异化的品牌框架」的品牌资产衡量体系研究文献,面向品牌营销从业者、市场调研人员、企业品牌管理者及商科学习研究者。内容围绕品牌资产如何与财务结果直接…

2026/9/18 0:21:10

大型集团管控制度顶层设计:从权责矩阵到IT落地的完整路径

简介:这份大型集团管控制度顶层设计方案演示文稿,面向集团总部管理者、企业制度体系建设人员及战略规划岗位,系统梳理了集团总部的战略决策中心定位、六大核心能力,以及由自描述文件、基础性文件、战略和运营、治理和风控四部分构…

2026/9/18 0:16:10

射频天线工程师必备:电磁理论、匹配设计与TRP链路解析

简介:本资源为2021年vivo提前批射频天线方向校招笔试真题及详解文档,面向通信工程、电磁场与微波技术、电子科学与工程等专业的应届生及射频工程师备考者,聚焦无线通信终端天线核心考点与工程实践能力评估。文档完整呈现笔试原题(…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/16 22:55:57

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/16 22:56:09

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/16 22:56:16

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码