FEATURED · 精选文章

Grafana Tempo 架构解析:Kafka 如何作为写入路径的持久化 WAL

发布时间 / 2026/9/18 22:01:11
来源 / 创域科博编辑部
栏目 / 资讯中心
Grafana Tempo 架构解析:Kafka 如何作为写入路径的持久化 WAL Grafana Tempo 架构解析Kafka 如何作为写入路径的持久化 WAL【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempoKafka 是 Grafana Tempo 微服务模式下写入路径的骨架承担着分布式追踪系统中最关键的职责——持久化预写日志WAL。本文以 Tempo 官方架构文档为主体结合仓库源码系统讲解 Kafka 在 Tempo 中的架构角色、分区与消费组机制、保留策略与延迟监控以及完整的ingest.kafka配置参考与生产运维实践帮助读者深入理解并安全地部署、扩容和运维基于 Kafka 的 Tempo 写入链路。Kafka 在 Tempo 架构中的角色在 微服务部署模式 下Tempo 使用一个兼容 Kafka 的消息队列作为其写入路径的主干。任何 Kafka 兼容系统都可以工作Tempo 并不绑定特定实现。Kafka 的本质作用是一条持久的写入前日志durable write-ahead log, WAL位于 distributor分发器与下游消费者block-builder、live-store、metrics-generator之间distributor 写入 Kafka收到 trace 后先经过校验与限流再将数据写入 Kafkablock-builder 消费 Kafka将数据组织成 Parquet block 并刷写到对象存储live-store 消费 Kafka在内存中维护近期数据供查询metrics-generator 消费 Kafka可选从 trace 数据中派生指标。Kafka 带来的核心价值是写路径持久性的集中化一旦 Kafka 确认了一次写入Tempo 的各组件就可以在重启后恢复前提是恢复所需的记录仍处于 Kafka 保留窗口内。具体恢复行为如下block-builder从最后提交的 Kafka offset 继续消费live-store重新加载本地 WAL 与已完成的本地 block然后基于已提交的 offset 与配置的 replay window 从 Kafka 恢复消费如果本地数据缺失则在窗口内回放 Kafka 以重建近期查询状态。由于 Kafka 提供了持久性Tempo无需在写路径上跨实例复制数据因而可以采用复制因子为 1 的配置显著降低存储成本。这正是微服务模式下 Kafka 成为写入主干、而单体模式下无需 Kafka 的根本原因——单体模式下 distributor 直接在进程内把数据推送给 live-store 和 metrics-generator。部署模式的差异也可以从 部署模式文档 中的组件对照表看出ingest配置块在单体模式下不启用仅在微服务模式下作为写路径的 Kafka 连接配置存在。官方架构图 tempo-write-path.svg 直观展示了这条链路Application → Distributor → Kafka → Block-builder → Object storage。分区机制trace ID 哈希与 Tempo 分区环Kafka topic 被划分为多个分区。Tempo 的分区行为可以归纳为三个关键设计1. 按 trace ID 哈希分区distributor 对 trace ID 做哈希以确定目标活动分区。同一 trace 的所有 span 都会进入同一个 Kafka 分区这带来两个直接收益block-builder 可以在单个消费周期内构建包含某 trace 全部 span 的 blocklive-store 无需跨分区协调即可从单个分区提供完整 trace。2. Tempo 分区环partition ringTempo 维护自己的分区环将 Tempo 分区映射到 Kafka 分区。两者通常是一比一对应但分区环在逻辑上独立于 Kafka 的分区元数据。这意味着 Tempo 可以自主控制分区的状态pending / active / inactive、所有权哪个 live-store 拥有该分区以及生命周期管理创建、激活、停用分区而不必修改 Kafka 配置。关于分区状态的详细转移规则参见 分区环文档。每个活动的 Kafka 分区由恰好一个 block-builder 实例和每个可用区一个 live-store 实例消费。3. 分区的扩缩容Kafka 分区数量决定了 block-builder 和 live-store 的最大并行度——每个活动分区只被每种消费者类型的恰好一个实例拥有。topic 的分区数可以远多于 Tempo 当前活动的分区数在 topic 现有容量内扩容直接增加 live-store 副本数并相应调整 block-builder 容量即可无需改动 Kafka topic目标活动分区数超过 topic 分区数必须先为 Kafka topic 增加分区再扩容 Tempo。block-builder 与 live-store 基于实例序号ordinal进行分区分配额外的 Kafka 分区会保持空闲直到 live-store 激活对应的 Tempo 分区。从源码看block-builder 的分区分配由 modules/blockbuilder/config.go 中的partitions_per_instance与assigned_partitions两个配置项控制前者按实例序号自动计算归属分区后者提供实例 ID 到分区列表的显式映射。消费组三类消费者独立推进Tempo 针对同一个 Kafka topic 运行多个相互独立的消费组消费组组件用途block-builderBlock-builder为长期存储构建 blocklive-storeLive-store为查询提供近期数据metrics-generatorMetrics-generator从 trace 数据派生指标每个消费组各自跟踪自己的 offset。block-builder 与 live-store 独立、按各自节奏消费同一份数据——慢的 block-builder 不会影响 live-store 的可用性反之亦然。这种解耦是微服务架构独立扩缩容的基础。值得说明的是block-builder/live-store/metrics-generator 是文档层面的消费组语义名称。在实际实现中pkg/ingest/config.go 的GetConsumerGroup()方法表明当consumer_group配置为空推荐做法时Tempo 直接使用实例 ID 作为消费组名以保证唯一性若配置了含partition占位符的消费组名则会在运行时替换为实际分区 ID。live-store 在启动时通过 modules/livestore/live_store.go 中的ingest.LiveStoreConsumerGroupID()生成其消费组 ID。这也解释了运维文档中保持 live-store StatefulSet 名称与序号稳定的告诫——改名会改变消费组身份可能触发数据回放。保留策略与 offset 管理Kafka 的保留策略决定了消费者可以回放多远。配置保留时长时需要覆盖两类需求block-builder 的消费周期时间外加故障与重启的缓冲live-store 启动时的 replay window。如果消费者落后于 Kafka 的保留窗口它将失去回放已错过数据的能力。因此持续监控消费延迟consumer lag是 Kafka 后端运维的底线要求。消费延迟的关键指标Tempo 通过ingest包的两个指标暴露每个消费组每个分区的延迟tempo_ingest_group_partition_lag{groupconsumer-group} tempo_ingest_group_partition_lag_seconds{groupconsumer-group}tempo_ingest_group_partition_lag按记录数records计量的每分区延迟tempo_ingest_group_partition_lag_seconds按墙上时钟秒计量的延迟。后者更适合与保留时长直接对比。指标的更新间隔由配置项consumer_group_lag_metric_update_interval控制默认 1 分钟置 0 可关闭计算与导出。相关指标还可在 block-builder 与 live-store 组件文档中查到例如tempo_block_builder_fetch_errors_totalKafka 拉取错误和tempo_live_store_lagged_requests_total因 Kafka 延迟而无法保证完整结果的请求。配置 Kafka 连接Kafka 连接设置统一配置在ingest区块下。最小配置只需地址与 topicingest: kafka: address: kafka:9092 topic: tempo-traces其中address只需提供一个 bootstrap 地址Tempo 会从 Kafka 元数据中发现 topic 的 broker。完整配置参考以下表格汇总了ingest.kafka下的主要配置项、默认值与说明均来自 pkg/ingest/config.go 中KafkaConfig的注册逻辑RegisterFlagsWithPrefix可作为配置参考配置项默认值说明addresslocalhost:9092Kafka 后端地址bootstrap 地址topic空Kafka topic 名称必填client_id空Kafka 客户端 IDclient_rack空客户端机架标识对应 Kafkaclient.rack可设为实例所在可用区以就近读取KIP-392减少跨可用区 Kafka 流量dial_timeout2s建立到 Kafka broker 连接的最大耗时write_timeout10s等待写入请求被 Kafka 成功提交的时长sasl_mechanismPLAINSASL 认证机制支持PLAIN、SCRAM-SHA-256、SCRAM-SHA-512、OAUTHBEARER、AWS_MSK_IAMsasl_username/sasl_password空SASL 用户名与密码须成对配置才能启用 SASLtls_enabledfalse为 Kafka 客户端连接启用 TLSconsumer_group空推荐消费者跟踪 offset 的消费组为空时 Tempo 用实例 ID 保证唯一性含partition占位符时替换为实际分区 IDconsumer_group_offset_commit_interval1s消费者向 Kafka 提交已消费 offset 的频率启动时用于从上次位置继续消费auto_create_topic_enabledtrue若 topic 不存在则自动创建生产环境建议预创建 topic 并置为falseauto_create_topic_default_partitions1000自动创建 topic 时尝试设置 Kafka broker 的num.partitions集群级设置best-effortproducer_max_record_size_bytes约 16 MB单条 Kafka record 的最大数据量超过会被拆分强烈建议保持默认producer_max_buffered_bytes1 GiB未确认的缓冲记录上限达到后 produce 请求失败0 表示禁用限制producer_compression空生产者压缩算法none、gzip、snappy、lz4、zstd为空时使用 Kafka 客户端默认偏好target_consumer_lag_at_startup2s启动时消费者尽力达到的最大延迟best-effortmax_consumer_lag_at_startup15s启动时消费者被认为追平并进入 ACTIVE 状态、通过就绪检查的保证最大延迟disable_kafka_telemetryfalse禁用 KIP-714 Kafka 客户端指标consumer_group_lag_metric_update_interval1m延迟指标的更新频率0 表示关闭认证与 TLS 配置示例以 SCRAM-SHA-512 加 TLS 为例ingest: kafka: address: KAFKA_BOOTSTRAP_ADDRESS topic: tempo-traces auto_create_topic_enabled: false sasl_mechanism: SCRAM-SHA-512 sasl_username: ${KAFKA_USERNAME} sasl_password: ${KAFKA_PASSWORD} tls_enabled: true使用环境变量时需传-config.expand-envtrue。对于私有 CA需挂载 CA 包并设置tls_ca_path双向 TLS 还需tls_cert_path与tls_key_path生产环境不要使用tls_insecure_skip_verify。从源码的校验逻辑pkg/ingest/config.go 的Validate()可以确认几条边界规则address与topic均不可为空target_consumer_lag_at_startup与max_consumer_lag_at_startup必须同时为 0 或同时大于 0且前者不能大于后者PLAIN/SCRAM 的 username 与 password 必须成对出现producer_max_record_size_bytes被限制在 1 MiB 到约 16 MB 之间。此外OAUTHBEARER与AWS_MSK_IAM机制分别要求静态凭据、文件路径、HTTP socket 路径三者恰好配置其一。完整的认证字段参见 配置 Kafka 兼容后端指南 与 ingest 配置参考。生产环境规划topic、分区数与保留时长Tempo 为所有租户使用一个共享的 trace 数据 topic。规划要点如下详见 configure-kafka.md分区数估算Kafka topic 分区数是活动 Tempo 分区数的上限而非 live-store / block-builder 副本数的必需要求。可按峰值吞吐估算最小活动分区数minimum_active_partitions ceil(peak_ingestion_bytes_per_second / 10 MB/s)topic 分区数必须不小于最大 live-store 副本数但可以显著多于当前需要以备未来增长。注意Apache Kafka 支持增加现有 topic 分区数但不支持原地减少其他 Kafka 兼容后端行为可能不同。block-builder 副本数的估算默认block_builder.partitions_per_instance: 1block_builder_replicas ceil(active_partitions / partitions_per_instance)基于序号的分配方式下每个 block-builder 认领partitions_per_instance个连续分区需保证topic_partitions block_builder_replicas * partitions_per_instance保留时长与容量使用基于时间的删除策略delete不要用日志压缩compaction后者可能在 Tempo 处理之前就删掉记录24 小时保留期是生产环境的合理起点。默认live_store.complete_block_timeout为 20 分钟重启的 live-store 可能回放该时长的两倍窗口因此保留期不要低于 40 分钟保留期必须覆盖 block-builder 最大故障与追赶时间并覆盖 live-store 的回放窗口原始保留数据量估算retained_bytes sustained_ingestion_bytes_per_second * retention_seconds需额外计入复制、记录开销与余量且不要让基于大小的保留策略缩短恢复窗口。最大消息大小Tempo 可产生最大16000000字节16 MB的 Kafka record 批次。Apache Kafka 需将 topic 的max.message.bytes设置为至少16000000message.max.bytes控制 broker 级默认值其他系统需设置等效的记录批次上限。创建 topicApache Kafka 的创建命令示例tempo-traces也是社区tempo-distributedHelm chart 的默认 topic 名kafka-topics.sh --bootstrap-server KAFKA_BOOTSTRAP_ADDRESS \ --create \ --topic tempo-traces \ --partitions KAFKA_PARTITION_COUNT \ --replication-factor 3 \ --config min.insync.replicas2 \ --config cleanup.policydelete \ --config retention.ms86400000 \ --config max.message.bytes16000000Tempo 的身份identity需要以下权限描述集群与 topic 元数据distributor 对 topic 的写入权限block-builder、live-store、metrics-generator 对 topic 的读取及消费组 offset 的读写权限。由于各组件共享 Kafka 配置通常一个身份即可拥有全部三类权限。启用自动创建还需要 topic 创建权限与集群 alter-configuration 权限——生产环境建议预创建 topic 并设置auto_create_topic_enabled: false。安全扩缩容实践不建议直接将通用 HPA 挂到 live-store / block-builder 的 StatefulSet 上因为直接缩减副本会绕过分区排空partition draining流程。扩容确保 Kafka topic 分区数达到目标值不足则先加分区扩容 live-store 并按需调整 block-builder 容量以匹配新增活动分区验证分区所有权与延迟。不要将 live-store 扩到超过 Kafka topic 分区数。缩容社区tempo-distributedchart 尚未自动化 live-store / block-builder 的分区感知缩容因此不要先缩减 StatefulSet 副本而是针对每个待移除的最高序号 live-store 依次执行向该 Pod 的/live-store/prepare-partition-downscale端点发送POST等待 block-builder 提交该分区剩余的 Kafka 记录、记录到达对象存储且近期查询不再依赖该 live-store向 Pod 的/live-store/prepare-downscale端点发送POST缩减liveStore.replicaslive-store 移除后按partitions_per_instance缩减blockBuilder.replicas。若partitions_per_instance 1移除某个 block-builder 前必须排空其全部被分配分区。缩容期间保持 Kafka topic 分区数不变未使用分区可留待后续扩容复用。切勿重命名 live-store StatefulSet 或改变其序号否则会改变消费组身份并触发数据回放。监控与故障排查部署完成后建议执行三项验证检查连接 / 认证 / TLS / topic 元数据错误并核对每个分区的副本与 ISR向 distributor 发送一条 trace 并通过 query frontend 查询确认每个活动分区都有 live-store 与 block-builder 所有者。Tempo Vulture 可提供持续的写入与查询验证。至少应采集以下指标并据此告警在消费延迟接近保留期前触发告警# Kafka 写入吞吐。 sum(rate(tempo_distributor_kafka_write_bytes_total[5m])) # distributor 产生的失败记录。 sum by (reason) (rate(tempo_distributor_produce_failures_total[5m])) # 消费延迟秒。 max by (group, partition) (tempo_ingest_group_partition_lag_seconds) # block-builder 拉取错误。 sum(rate(tempo_block_builder_fetch_errors_total[5m])) # live-store 就绪状态。 min(tempo_live_store_ready)仓库中的 tempo-mixin 包含了针对 Tempo Kafka 生产者和消费者的仪表盘与告警不监控 Kafka broker 自身健康后者需使用后端自带的监控集成。常见故障与处置见下表症状处置MESSAGE_TOO_LARGE或写入被拒将后端等效的max.message.bytes设置为至少16000000topic 未创建显式创建 topic或启用自动创建并授予所需权限认证或 TLS 错误检查 SASL 机制、凭据、CA 包、客户端证书与 broker 主机名live-store / block-builder 不消费检查分区所有权、topic 元数据、Kafka 权限与拉取错误消费延迟持续增长检查 Tempo 资源、对象存储吞吐、broker 限流与分区并行度Kafka 不可用时写入失败恢复 Kafka 并确保 trace 客户端对失败的导出进行重试默认 Kafka 写入超时为 10 秒从源码看 Kafka 客户端的实现细节结合 pkg/ingest/config.go 的实现还可以理解几个与运维直接相关的底层行为写入确认语义configure-kafka 文档明确指出 Tempo 使用 Kafka 协议最强的确认模式acksall并等待后端确认每次写入后才向客户端返回成功响应——这与 distributor 组件文档 所述写入仅在 Kafka 返回成功后视为成功完全一致保证了客户端一旦收到成功响应数据就已持久化生产者缓冲与批大小单批最大 16 MBproducerBatchMaxBytes单条 record 数据上限约为 16 MB 减去约 16 KB 序列化开销未确认缓冲上限默认 1 GiB达到后 produce 请求失败自动创建 topicauto_create_topic_enabled开启时Tempo 启动时会 best-effort 地尝试将 broker 的num.partitions改为auto_create_topic_default_partitions默认 1000失败仅记录日志、不影响启动启动追平机制target_consumer_lag_at_startup与max_consumer_lag_at_startup控制消费者在启动时追赶 lag 的行为两者都设为 0 可关闭该等待逻辑消费组只有追平后才能进入 ACTIVE 状态并通过就绪检查这是分布式协调中防止带病服务的关键设计。相关资源部署模式分区环配置 Kafka 兼容后端Block-builder 组件Live-store 组件Distributor 组件ingest 配置实现源码block-builder 分区分配配置源码【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻