Grafana Tempo 3.1.0 于 2026-09-29 发布:vParquet3 写入被直接拒绝,vParquet5 成为新的默认块格式。 这条版本更新落在「前置部署」Forward Deployed Engineer(FDE)的可观测性交付段与 Day 2 运维段:智能体与微服务的「链路数据」一旦落进 Tempo,客户的「合规删除」、采样成本与故障归因都压在这套「追踪后端」上。这次发布的每一项门槛改动都要求「前置部署」Forward Deployed Engineer(FDE)在升级窗口内先动手改配置,而不是升级完再看报错。对把 Tempo 装进客户 air-gapped 环境的「前置部署」Forward Deployed Engineer(FDE)来说,这篇文章的价值是给出改动前后各是哪一种行为、以及哪一条改动没有回滚路径。 Grafana Tempo 3.1.0 的正式 tag 在 2026 年 9 月 29 日 UTC 17 时前后推送,GitHub 的 releases 源给出的时间戳是 2026-09-29T17:07Z,该 release 被标为 Latest。发布页显示这个 tag 推送之后主线又累积了 44 次提交。官方发布说明由 Tempo 团队署名,GitHub release 页的贡献者栏写作 heytrav、zachfi 与另外 21 位贡献者,合计 23 人。构建链升级到 Go 1.27.1。 改动规模可以用 PR 编号数出来。官方 changelog 一共出现 131 处 PR 引用,去重后是 124 个唯一 PR 编号,其中 Features 段 9 处、Enhancements 段 52 处、Breaking Changes 段 5 处、Changes 段 8 处、Security fixes 段 2 处、Bugfixes 段 55 处。这是典型的「列表很长、真正的硬门槛只有五条」型发布。 第一处硬门槛是「块格式」的写入侧被直接封死,对应 PR 7858。改动前 Tempo 允许把存储写格式配成 vParquet3:vParquet3 从 Tempo 2.10 起就被标记弃用,3.0 又重述了一次,但代码里没有任何东西阻止它被实际使用。改动后 Tempo 拒绝以 vParquet3 作为「写入格式」启动,而且压缩器也不再让已有的 vParquet3 块参与合并。读取已有的 vParquet3 块不受影响,官方明确说不需要格式转换。 同一处还有默认值变更,这是最容易漏掉的一条。3.1 之前新写入的块默认是 vParquet4,3.1 之后新块默认写成 vParquet5,对应 PR 7775。官方写明不需要数据迁移:升级后新块按 vParquet5 写,已有的 vParquet4 与 vParquet3 块继续可读。想继续写 vParquet4 的组织必须显式设置 storage.trace.block.version 为 vParquet4,这个配置项在 YAML 里的层级是 storage 下的 trace 下的 block 下的 version。 第二处硬门槛是实验性的 Redis 缓存客户端被整体重写,行为差异最大,对应 PR 7337。改动前的路由模式由端点数量推断,当集群端点解析到单个主机时会静默退回单节点客户端,官方举的例子正是 AWS ElastiCache 的 configuration endpoint。改动后 Redis Cluster 成为默认路由模式,想退回单节点必须在配置里写 single_node 为 true,命令行对应的开关是 -redis.single-node。Redis Cluster 部署现在要求 Redis 7 及以上,因为 Tempo 依赖 COMMAND INFO 广告出来的 multi_shard 请求策略来并行扇出「跨槽位」的 MGET 与 DEL。 TLS 配置的改法是这一版最需要提前排查的地方。改动前只有 tls_enabled 与 tls_insecure_skip_verify 两个键,改动后换成 dskit 风格的 TLS 块,键名包括 tls_cert_path、tls_key_path、tls_ca_path、tls_server_name、tls_insecure_skip_verify、tls_cipher_suites 与 tls_min_version。官方原文写明:无效的 TLS 设置现在会失效即拒,而改动前只会静默降级成明文。这一条对金融与政府类客户的验收尤其关键,因为静默降级意味着你以为在加密、实际没有。 Redis 侧还有一批键被删或被改名,逐条列出来。Sentinel 支持被完全移除,master_name、sentinel_username、sentinel_password 三个 YAML 键,以及 -redis.master-name、-redis.sentinel-username、-redis.sentinel-password 三个命令行参数,全部不再存在。两个连接池键改名以对齐 go-redis v9 的接口:idle_timeout 改成 conn_max_idle_time,max_connection_age 改成 conn_max_lifetime。新增的路由选项包括 route_by_latency、route_randomly、read_only、max_redirects 与 min_idle_conns,另有一个可配置的 max_item_size 上限,以及一个可配置的「缓存淘汰」上限。「跨槽位」的 MGET 与 DEL 改成在分片间并行扇出,MSet 从 TxPipeline 换成 Pipeline,因此「跨槽位」写入不会再因为 CROSSSLOT 失败。 第三处门槛是「查询分片」的度量单位换了,对应 PR 7105。改动前 query_shards 默认 50,每次按 trace ID 查询都被切成固定 50 个作业,与租户实际有多少块无关,所以这个值必须按同一个单元里最大的租户来调,租户变大变小还要重新调。改动后新增 query_frontend.trace_by_id.blocks_per_shard,默认 30,按租户当前的块数动态算分片数,并且只要它非零就优先于 query_shards。要保留改动前的固定分片行为,把它设成 0 就会退回 query_shards。官方补了一句边界:算出来的分片数不会超过 query_frontend.max_outstanding_per_tenant,所以不会压垮查询队列。 同属默认值变更的还有 query-frontend 的 gRPC 包大小,对应 PR 7615。query-frontend 的 max_grpc_streaming_packet_size 默认值从 2 MiB 降到 1 MiB。如果你的下游依赖大于 1 MiB 的流式 gRPC 响应,必须在配置里显式写回原值,否则会在传输层看到截断或报错。 第四处门槛是 Memcached 的「空闲连接」默认值,对应 PR 7671。改动前空闲超过 2 分钟的连接一律被关闭,改动后默认不再关闭,并且 max_idle_conns 的默认值从 16 提高到 100。官方给的根因很清楚:改动前每一波读取高峰都要以一阵新建连接开头,这既抬高 p99 延迟也直接造成客户端侧超时。要恢复改动前的行为,把 max_idle_conns 设回 16 并把 min_idle_conns_headroom_percentage 设成 0。需要提醒的是,这组新默认值会抬高每个 Memcached 服务端的常驻连接数,容量规划要一起改。 把被移除与改名的东西汇总一遍,方便逐条对账。vParquet3 写入被禁止;Redis Sentinel 三个键与三个参数被删;Redis 的 idle_timeout 与 max_connection_age 改名;trace-by-ID 的 query_shards 被 blocks_per_shard 取代;集群级的 query_frontend.trace_by_id.span_pruning_enabled 开关被删除,修剪改成按请求用 span_pruning 参数开启;tempo-cli 的实验命令 trace-diff 与 MCP 服务器的 trace-diff 工具一并改名为 traces-diff。 新增能力里对合规交付最直接的是「重删作业」可以按查询提交,对应 PR 7663。改动前 Tempo 3.0 的追踪重删必须提供一份显式的 trace ID 列表,这意味着一场敏感数据事件要先把每一条受影响的 trace 找出来。改动后可以改用 TraceQL 选择器提交,按属性匹配而不是枚举 ID。官方同时把显式 trace ID 列表的上限压到 1000 条,超过就报错并提示改用查询选择器。 这条 1000 条上限写在 PR 7808 里,它的根因值得抄进交付文档。官方解释是每个重删作业都携带整批的 trace ID 列表,提交成本按 ID 数乘以块数增长;几百万个 16 字节 ID 打在一个有几万个块的租户上,单次调度就能产生 TB 级调度流量。此前的 gRPC 消息上限只是把单次提交挡在约 580 万条附近,那是压力下才暴露的失败,不是一个声明过的边界。查询选择器在 worker 端按块解析,不往任何作业载荷里加东西,这是它同时解决规模与成本的机制。 重删还补了一处安全缺口和一处静默绕过,两条都必须知道。安全那条是跨租户「越权路径」:重删作业的目标租户现在只从已鉴权的请求上下文 X-Scope-OrgID 取,客户端请求体里自带的 tenant_id 字段被忽略,官方公告编号是 GHSA-jw7f-3cgp-hgrr。静默绕过那条更隐蔽:改动前一个重删批次在最后一个作业完成的瞬间就被移除,正好卡在这个窗口里由压缩产生的块会逃过重删;改动后完成的批次会先进入一段短暂静默期再移除,期间租户的「块压缩」保持关闭,直到重扫覆盖到它。 窗口化重删是本版最需要警惕的一条,官方用 Caution 级别写了出来。改动后重删可以带 --start 与 --end 把一个大租户切成片来删,但官方明确说:在所有调度器与 worker 都升到 3.1 之前,不要提交带时间窗口的重删。旧版 worker 会忽略时间窗口字段,把它拿到的块里所有匹配的 trace 全部删掉,既不报错也没有恢复手段。官方另有一条限制:窗口不能与 --trace-id 组合使用,因为按 ID 定位的 trace 没有时间界,两者叠加会把每条列出的 trace 只从与窗口重叠的块里删掉、其余留在原地却报告成功。 TraceQL metrics 这次补上了两块长期缺口,对「链路采样」成本敏感的团队价值最大。第一块是「算术运算」:加、减、乘、除都能用在聚合之间,于是可以把多个聚合写在一条查询里,官方示例是用错误状态的速率除以全量速率一次算出错误率,而不必把两个结果拉回客户端再拼。第二块是「采样外推」:在 10% 的「采样概率」下,一条空选择器的 rate() 大约只报 50 每秒,而真实的未采样速率是 500 每秒,开启外推后 Tempo 会用每个 span 上记录的采样概率把量级还原回来。 外推的开关与边界要一起记。它是一个实验性查询提示,写法是 with(extrapolate=true)。它只对 vParquet4 及以上的块生效,查 vParquet3 块时这个提示被忽略。机制上,当 span 的 tracestate 里带 OpenTelemetry 的概率阈值时,每个匹配的 span 按「采样概率」的倒数贡献权重,作用到 rate、count_over_time、sum_over_time、avg_over_time、histogram_over_time、quantile_over_time 与 compare 这几类聚合上;min_over_time 与 max_over_time 不受影响。 新增的实验能力里还有「追踪对比」,通道有三个:HTTP API、命令行与 MCP 服务器。它用来比较同一条 trace 的基线与候选两次运行之间的差异,属于典型的回归定位工具。API 默认输出 trace-patch-v0 的完整 span 级补丁;trace-summary-v0-composed 格式额外给一份紧凑摘要,并把补丁上限压在 64 KiB,超出时直接声明补丁被省略,而不是静默截断。对比对 span 时长用容差匹配,相对容差 20%、下限 1 毫秒;数值属性走白名单加 5% 相对容差,目的是让两次跑之间的计时噪声不产生误报。两条 trace 的合计大小会按租户的 max_bytes_per_trace 校验,超限返回 429。MCP 端新增的 traces-diff 工具默认给紧凑摘要加 64 KiB 以内的补丁。 Kafka 写入路径这次补齐了社区独立贡献的三块缺口。改动前 Tempo 的 Kafka 客户端只支持 SASL PLAIN,不能加密传输、不能优先本机架、不能选「压缩编解码」,需要 TLS 或更强 SASL 机制的集群根本用不了这条路径。改动后新增 SCRAM-SHA-256、SCRAM-SHA-512、OAUTHBEARER 与 AWS_MSK_IAM 四种机制,加上 TLS 与双向 TLS;OAUTHBEARER 与 AWS_MSK_IAM 的凭证可以静态写入、从 JSON 文件读、或走 Unix domain socket 取,对应「凭证来源」的三种接法。 Kafka 的另外两块改动分别是「机架感知」与生产端压缩。client_rack 打开 KIP-392 的「机架感知」拉取,让消费者从同可用区的副本取数而不是总跨区去分区主节点,官方说这能压低高吞吐管道上的跨区流量成本。ingest.kafka.producer_compression 可以覆盖生产端的「压缩编解码」,取值是 none、gzip、snappy、lz4、zstd 五个且不区分大小写,不设就保持客户端自己的默认偏好。官方点明 Azure Event Hubs 只支持 gzip,这一项「生产者压缩」就是为它加的。还有一条运维侧的默认行为变更:分发器现在会在 2 倍心跳超时之后自动遗忘不健康实例,默认心跳超时对应的是 10 分钟,因此非优雅终止的 Pod 不再需要人工去 /distributor/ring 点 Forget。 服务拓扑与跨度修剪这两块也各有一组新增。metrics-generator 新增一个 opt-in 的连接信息存在性 gauge,配合新增的 service-graphs 子处理器,在重度采样下仍能保住服务拓扑的可见性,配套新增 tempo-service-graph.json 面板。服务图现在识别 db.system.name 这个属性,它是 OpenTelemetry 语义约定 v1.30.0 从 db.system 改名而来,新旧两个属性都保留支持,所以升级到新 SDK 之后数据库节点不会消失。追踪按 ID 查询的 v2 端点新增「跨度修剪」,用来做「响应裁剪」,要在请求里显式写 span_pruning 为 true 才生效;另有实验性的 span_pruning_enabled_by_default 配置项与按租户的 span_pruning_enabled 覆盖项,请求里显式写的值优先级最高,也就是说「丢弃策略」最终由请求参数决定。 性能侧公布了几个可以直接对照的数字。「行组扫描」改动前会把一个块的所有行组走完再按限额截断,改动后一达到调用方的限额就停止扫描,官方给的实测是在一个 2.4 GB 的块上、为一个高基数的专用属性收集值,单次耗时从 67 毫秒降到 9 毫秒。块列表更新从块数乘租户数的双重循环改成两次预建映射,复杂度由 O(N·M) 降到 O(N+M)。块选择器的热循环不再每次比较都重算专用列哈希,改为把哈希缓存进时间窗选择器。metrics 查询的快速 span-only 取数路径从 Tempo 3.0 的实验特性转成默认开启,可按租户用 metrics_spanonly_fetch 关闭,或按查询用 with(spanonly_fetch=false) 关闭,后者要求该租户先开启 unsafe_query_hints。另有一条与缓存相关的修复写在 PR 7617:改动后一个块里没有匹配值的空结果也会被缓存,不再每次查询重扫。 有几条「不升级就会算错」的正确性修复值得单独列。第一,经典直方图的 _sum 序列在高频创建与淘汰的序列上会被 increase() 与 rate() 少报,修复见 PR 7811,根因是改动前 _count 与 _bucket 在建序列时植入了零样本而 _sum 漏了这一步。第二,native 与 both 两种直方图模式下,缺少 trace ID 的 span 会被挂上一个 traceID 标签为空的 exemplar,在 Grafana 里表现为无法定位的空标签。第三,vParquet5 的快速取数层对 trace:rootService、span:childCount 与数组操作返回过错误结果。第四,瞬时 metrics 查询与区间 metrics 查询之间存在一处缓存冲突,导致结果串味;另有 query-frontend 在 max_batch_size 大于 1 时派发请求批次的「数据竞态」修复。第五,tag value 的限额参数以前只在 query-frontend 生效,每个块仍被无上限扫描,改动后才把 limit 与 maxStaleValues 一路传到 querier 与 live-store。第六,TraceQL 的 =nil 查询曾经漏掉部分值。 安全侧的收口也要提一句。官方把 Go 升到 1.27.1,并连带升级了 vendored 的 golang.org/x/net 与 golang.org/x/text,一共覆盖 7 个 CVE 编号,其中包括 CVE-2026-56852 与 CVE-2026-39822。所有四个发布镜像 tempo、tempo-vulture、tempo-query 与 tempo-cli 现在都用 cosign 做无密钥签名,并附 SLSA「构建溯源」,可以在部署前做「签名验证」与「构建证明」核对。对需要 air-gapped 交付的「前置部署」Forward Deployed Engineer(FDE)来说,这是把镜像放进客户私有仓库之前可以先做的一次供应链核对。 局限部分先讲官方自己标注的。追踪对比与追踪摘要都被标为实验特性,官方原文写明工程与 on-call 支持不可用,未来版本可能变更或移除,不建议在生产环境使用。span_pruning_enabled_by_default 同样是实验配置项,不写就不生效。报告 TraceQL 引擎数据量的 engine_bytes_tracking 覆盖项默认关闭。还有一条容易踩:Grafana 界面没有跨度修剪的开关,所以一旦把默认值打开,Grafana 用户会拿到被修剪的 trace 且无法在界面上关掉,要取未修剪的 trace 只能直接调 v2 API 并传 span_pruning 为 false。 素材本身也有空白,需要如实说明。本次可核实的材料只有三份且全部来自 Grafana Labs 一家:GitHub release 页、官方文档的 v3.1 发布说明、官方升级指南。没有第三方对 vParquet5 的写放大、读延迟或对象存储成本做过独立测量,官方给出的 67 毫秒到 9 毫秒也只是单个 2.4 GB 块的例子,不是一组基准数据。vParquet3 块不再参与合并这一点,官方只说读取不受影响,没有说明这批块长期停留在对象存储上的成本影响,也没有给出把它们迁移掉的建议。KEDA 自动扩缩部分,官方提到 live-store 打开 KEDA 会自动打开 rollout_operator_replica_template_access_enabled,但没有说明这个权限模板具体授予了什么。 还有三类场景本版没有覆盖,别默认它们能用。第一,跨度修剪只在 trace-by-ID v2 端点可用,Grafana 界面走的不是这条路径,所以在界面上看不到差别。第二,「采样外推」只在 vParquet4 及以上的块上生效,历史 vParquet3 块的查询会静默忽略这个提示。第三,窗口化重删只在全部调度器与 worker 同版本时才安全,混合版本升级期间应当只做无窗口的全量重删。 谁该行动、按什么顺序动手,这里给一份可直接执行的顺序。已经在生产跑 Tempo 的团队,升级前先跑三条检查:确认 storage.trace.block.version 当前不是 vParquet3;确认 Redis 缓存属于哪一种路由并把配置块按新键名重写;确认自己有没有依赖固定的 trace-by-ID 分片数。正在给客户做交付的「前置部署」Forward Deployed Engineer(FDE),把这三条检查直接写进升级前的 Site Survey 模板,比升级后排查便宜得多。 具体步骤分五步,每一步都有对应的配置项。第一步,块格式:默认会写成 vParquet5,要写 vParquet4 就在 storage 下的 trace 下的 block 下把 version 写成 vParquet4。第二步,Redis 路由:单节点部署加 single_node 为 true,否则默认按 Cluster 路由,且 Cluster 要求 Redis 7 及以上。第三步,Redis 的 TLS 与连接池:把 TLS 配置改成 dskit 风格块并逐个替换键名,同时把 idle_timeout 改成 conn_max_idle_time、max_connection_age 改成 conn_max_lifetime,并确认无效配置现在是失效即拒而不是降级明文。第四步,按需写回默认值:需要大于 1 MiB 流式 gRPC 响应就显式设 max_grpc_streaming_packet_size;要保留旧连接行为就把 max_idle_conns 设成 16 并把 min_idle_conns_headroom_percentage 设成 0。第五步,改名对齐:把命令行与 MCP 客户端里对 trace-diff 的调用改成 traces-diff,并在客户端侧删掉那个已废弃的集群级「修剪开关」。 回滚与退出方式要按后果分级,不能一概而论。块格式这一侧不可简单回退:一旦写出 vParquet5 块,回退到旧版本之前要确认目标版本能读 vParquet5;官方给的迁移方向是新块变更、旧块保持,所以回滚的安全边界是回退期间不要写新数据。Redis 侧的回滚是把 single_node 与旧键名改回去,前提是目标版本还没删掉 Sentinel 支持,一旦回退到 3.1 之后再想用 Sentinel 就没有这条路了。跨度修剪的回滚是关掉 span_pruning_enabled_by_default,或在请求里传 span_pruning 为 false。重删作业在 apply 模式执行过之后无法撤销,官方没有提供反向操作,这是本文里唯一一条没有回滚路径的动作,所以在混合版本环境下务必先确认全部组件同版本。 适用条件也要写清楚,避免把结论套到不适用的部署上。本文的结论成立前提是以微服务模式部署、启用 Kafka 写入路径与 Redis 缓存的 Tempo 集群;单二进制模式会跳过 Kafka 这一整段。KEDA 自动扩缩需要 Kubernetes 与 KEDA 同时就位,且指标源是多租户系统时必须设 autoscaling_prometheus_tenant。跨度修剪只在按 ID 查询的 v2 端点可用。「采样外推」只在 vParquet4 及以上的块上生效。窗口化重删只在所有调度器与 worker 同版本时才安全。 升级自检清单,逐条勾选,每一条都对应上面某一段的结论。 - FDE(前置部署 Forward Deployed Engineer):确认 storage.trace.block.version 不是 vParquet3,否则会拒绝启动。 - FDE(前置部署 Forward Deployed Engineer):接受新块默认写成 vParquet5,旧块继续可读。 - FDE(前置部署 Forward Deployed Engineer):要写 vParquet4 就在 block 下显式写 version。 - FDE(前置部署 Forward Deployed Engineer):确认不需要做格式转换,官方说无数据迁移。 - FDE(前置部署 Forward Deployed Engineer):单节点 Redis 加 single_node 为 true。 - FDE(前置部署 Forward Deployed Engineer):Redis Cluster 确认版本在 7 及以上。 - FDE(前置部署 Forward Deployed Engineer):删掉 master_name 与两个 sentinel 键。 - FDE(前置部署 Forward Deployed Engineer):把 idle_timeout 改成 conn_max_idle_time。 - FDE(前置部署 Forward Deployed Engineer):把 max_connection_age 改成 conn_max_lifetime。 - FDE(前置部署 Forward Deployed Engineer):把 TLS 配置改成 dskit 风格键名块。 - FDE(前置部署 Forward Deployed Engineer):确认无效 TLS 配置现在失效即拒,不再静默降级明文。 - FDE(前置部署 Forward Deployed Engineer):依赖固定分片数就把 blocks_per_shard 设成 0。 - FDE(前置部署 Forward Deployed Engineer):确认 blocks_per_shard 非零时优先于 query_shards。 - FDE(前置部署 Forward Deployed Engineer):需要大响应就显式设 max_grpc_streaming_packet_size。 - FDE(前置部署 Forward Deployed Engineer):把 max_idle_conns 与 min_idle_conns_headroom_percentage 按容量重算。 - FDE(前置部署 Forward Deployed Engineer):把 trace-diff 的调用改成 traces-diff。 - FDE(前置部署 Forward Deployed Engineer):删掉已废弃的集群级「修剪开关」。 - FDE(前置部署 Forward Deployed Engineer):把重删从枚举 trace ID 改写成 TraceQL 选择器。 - FDE(前置部署 Forward Deployed Engineer):确认单次显式 trace ID 提交不超过 1000 条。 - FDE(前置部署 Forward Deployed Engineer):确认混合版本期间不提交带时间窗口的重删。 - FDE(前置部署 Forward Deployed Engineer):确认重删目标租户来自 X-Scope-OrgID 而不是请求体。 - FDE(前置部署 Forward Deployed Engineer):确认 apply 模式重删没有回滚路径,执行前二次确认。 - FDE(前置部署 Forward Deployed Engineer):把采样外推限制在 vParquet4 及以上的块。 - FDE(前置部署 Forward Deployed Engineer):确认 Grafana 界面无法关闭跨度修剪。 - FDE(前置部署 Forward Deployed Engineer):核对 cosign 签名与 SLSA 构建证明。 - FDE(前置部署 Forward Deployed Engineer):把 7 个 CVE 修复写进客户的安全变更单。 - FDE(前置部署 Forward Deployed Engineer):确认 Azure Event Hubs 场景把生产者压缩设成 gzip。 - FDE(前置部署 Forward Deployed Engineer):确认 Kafka 集群已开 TLS 或更强的 SASL 机制。 - FDE(前置部署 Forward Deployed Engineer):把 vParquet3 块不再参与合并写进容量与成本评估。 - FDE(前置部署 Forward Deployed Engineer):把升级前后各条配置项做成对照表随交付归档。 原始来源: - https://github.com/grafana/tempo/releases/tag/v3.1.0 - https://grafana.com/docs/tempo/latest/release-notes/v3-1/ - https://grafana.com/docs/tempo/latest/set-up-for-tracing/setup-tempo/upgrade/