Grafana Tempo 感知可用区的 live-store 复制(Zone-aware live-stores)配置指南
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
Zone awareness(区域感知/故障域感知)是 Tempo 用于保证数据在多个故障域(下称"区域 zone")之间冗余复制、从而提升整体可用性的关键能力。本指南聚焦于 live-store(实时存储)场景下的 zone-aware 复制配置:它将 Tempo 的分区(partition)所有权按"每个区域一个 live-store"进行分配,使任一区域中的 live-store 不可用时,其他区域的 live-store 仍能继续为该分区提供查询服务。读完本文,你将理解 zone-aware live-stores 的工作原理(RF2 复制、读仲裁为 1 的机制)、如何在 Tempo 中为 live-store 与查询端配置感知可用区的路由,以及与此相关的 ring、partition ring 配置参数的含义与作用。
一、Zone awareness 是什么
Zone awareness 是一项确保数据跨故障域复制、从而提供更高可靠性的功能。这里的"故障域"(failure domain)完全由你自行定义,常见的有:
- 云厂商的可用区(availability zone,如 AWS 的
us-east-1a); - 数据中心(data center);
- 服务器机架(server rack)。
对 Grafana Tempo 而言,配置 zone awareness 后,系统会把 ring 中的每个实例标记到它所属的区域,并将数据副本放置到不同区域,从而避免"整个区域故障时所有副本同时不可用"的最坏情况。
Tempo 是一个"高吞吐、最小依赖"的分布式链路追踪后端(参见 README.md),zone awareness 与它的 ring 机制深度绑定:每个参与服务的实例会通过 key-value 存储(默认 memberlist)向 ring 注册自己的身份、地址与区域归属。
二、Zone-aware live-stores 的核心设计
每个分区由"每个区域一个 live-store"持有
当为 live-stores 开启 zone awareness 后,Tempo 的每个分区(partition)将由每个区域中的一个 live-store 持有(owned)。也就是说,若你部署了 3 个区域,那么每个分区会有 3 个 live-store 同时持有它——分别位于 3 个不同的区域。
这样做的好处是:当某个区域中的 live-store 不可用时,其他区域中持有同一分区的 live-store 可以继续为该分区提供查询服务,查询不会中断。
RF2 复制与读仲裁为 1
在这种设计下:
- 数据跨区域复制,副本数为 2(RF2):每个分区在两个不同区域中保有数据副本;
- 读仲裁(read quorum)为 1:查询端(querier)只需获得每个分区的一个live-store 的响应即可返回结果。
也就是说,虽然数据写入了两份,但查询只需要一份响应即可成功。这带来了一个重要收益:读路径无需进行数据去重(data deduplication),因为查询只依赖单一副本的结果,不会对来自多个副本的响应做合并比对。这一点同时降低了查询延迟(等待最少响应即可返回)与实现复杂度。
设计要点小结
| 设计维度 | 行为 |
|---|---|
| 分区所有权 | 每个分区在每个区域中恰有一个 live-store 持有 |
| 复制因子 | 跨区域 RF2,数据写入两个区域 |
| 读仲裁 | 每分区仅需 1 个 live-store 响应(quorum = 1) |
| 读路径去重 | 不需要;查询只取单副本结果 |
| 故障场景 | 单一区域 live-store 不可用时,其余区域副本继续服务查询 |
三、live-store 在 Tempo 中的角色与 ring 机制
live-store 模块概览
live-store 是 Tempo 的 livestore 模块提供的能力,负责从 Kafka 消费 trace 数据、在内存中维护实时数据分片(live traces)、并按块(block)完成与刷新到后端存储。与其相关的重要源文件包括:
- live_store.go:核心服务,同时管理分区 ring(partition ring)与读 ring(read ring);
- partition_ring.go:分区 ring 的配置与生命周期器(lifecycler)参数;
- partition_reader.go:按分区消费 Kafka、计算滞后(lag)并提交 offset 的读取器;
- config.go:live-store 全部配置项及其默认值。
两个 ring:分区 ring 与读 ring
从源码 live_store.go 可以看到,LiveStore 启动时会同时搭建两套 ring:
- 分区 ring(partition ring):基于
ring.NewPartitionInstanceLifecycler构建,用于管理"谁持有哪个分区"的所有权关系。每个分区可以有多位 owner(不同区域的 live-store 各占其一),这正是 zone-aware 复制的基础; - 读 ring(read ring / membership ring):基于
ring.NewBasicLifecycler构建,用于服务发现——live-store 实例注册到 ring 中,让查询端可以发现并连接。从 live_store.go 的实现可以看到,该 ring 的实例注册为ring.ACTIVE状态且不需要 token(注释明确说明"我们只需要在 ring 里以做服务发现")。
关键配置项instance_zone(源码定义于 pkg/ring/config.go)正是用于在 ring 中标记实例所属区域:BasicLifecyclerConfig中的Zone字段取自cfg.InstanceZone(参见 pkg/ring/config.go)。每个 live-store 实例只要配置了不同的instance_zone,就会被 ring 归属到不同区域,从而实现"每分区每区域一个 owner"的布局。
此外,分区读取器还通过tempo_live_store_partition_owned指标(带有partition与zone两个标签)暴露当前实例对分区的持有状态,方便运维直接观察每个分区在每个区域的所有权情况(见 partition_reader.go)。
四、如何配置 zone-aware live-stores
配置区域归属(instance_zone)
要让 zone awareness 生效,第一步是给每个 live-store 实例设置区域标识。Tempo 的统一配置结构(模块livestore的ring段)中对应字段为:
livestore: ring: # 必填:定义当前实例所属的故障域。 # 可以是可用区、数据中心或机架名,例如 "us-east-1a"、"dc1"、"rack-a"。 instance_zone: "us-east-1a"该配置的源码定义位于 pkg/ring/config.go:RegisterFlagsAndApplyDefaults中通过 flag-<prefix>.instance-availability-zone注册(例如-livestore.ring.instance-availability-zone),默认值为空字符串(即默认不感知区域)。它最终会被写入BasicLifecyclerConfig.Zone(pkg/ring/config.go),随心跳上报到 ring,供查询端按区域选择实例。
务必确保:同一分区副本所在的多个 live-store 实例必须配置互不相同的instance_zone,否则它们会落入同一故障域,区复制(RF2)的容灾效果将大打折扣。
分区 ring 的 KV 存储
分区 ring 的状态共享依赖于 KV 存储。从 partition_ring.go 可以看到,其默认 store 为memberlist(默认前缀collectors/),一般无需改动:
livestore: partition_ring: kvstore: store: memberlist完整的最小配置示例
结合 config.go 中RegisterFlagsAndApplyDefaults的默认值(如HeartbeatPeriod = 5s、HeartbeatTimeout = 1m),一个开启 zone-aware 的最小配置如下:
livestore: ring: heartbeat_period: 5s # 默认 5s,ring 心跳周期 heartbeat_timeout: 1m # 默认 1m,心跳超时判定实例不健康 instance_zone: "us-east-1a" # 关键:本实例所属区域,各副本实例必须互不相同 partition_ring: kvstore: store: memberlist # 默认 memberlist,无需手动指定也可 min_partition_owners_count: 1 # PENDING 分区转为 ACTIVE 所需的最少 owner 数 min_partition_owners_duration: 10s # 满足最小 owner 数后需持续的时间 delete_inactive_partition_after: 13h # INACTIVE 分区被删除前的等待时长其中min_partition_owners_count、min_partition_owners_duration、delete_inactive_partition_after三个参数在 partition_ring.go 中均有注释说明其映射关系:
MinOwnersCount→PartitionInstanceLifecyclerConfig.WaitOwnersCountOnPending;MinOwnersDuration→WaitOwnersDurationOnPending;DeleteInactivePartitionAfter→DeleteInactivePartitionAfterDuration。
对于 zone-aware 场景,建议min_partition_owners_count至少设为你的区域数量(例如 2 或 3),确保分区只有在每个区域都有 owner 之后才转为 ACTIVE 对外服务。
五、查询端如何感知区域:PreferredZone 与 zone sorter
仅让 live-store 感知区域还不够,查询端(querier)也需要按区域组织请求,尽量在本地/优先区域内完成查询。这一逻辑实现在 querier/partition_ring.go:
queryQuorumConfigForReplicationSets构造ring.DoUntilQuorumConfig,并通过queryPartitionRingZoneSorter(q.cfg.PartitionRing.PreferredZone)注入一个区域排序器(querier/partition_ring.go);- 排序器逻辑(querier/partition_ring.go)为:若
preferredZone非空,则把该区域排到最前优先尝试;其余区域打乱顺序以均衡负载。这样在"最小化请求 + 按区域优先"的配合下,querier 会优先访问同区域副本,区域不可用时再退回到其他区域副本。
querier: partition_ring: preferred_zone: "us-east-1a" # 优先查询该区域内的 live-store 副本 minimize_requests: true # 达到仲裁(每分区 1 个响应)后即停止多余请求minimize_requests与minimize_requests_hedging_delay直接映射到DoUntilQuorumConfig的对应字段(querier/partition_ring.go),用于控制达到 quorum=1 后是否立即终止其余 in-flight 请求。
六、zone-aware 复制的收益与适用场景
收益
- 高可用:单个区域(可用区/数据中心/机架)故障不会中断对应分区的查询,另一区域的副本继续服务;
- 低查询开销:读仲裁为 1,querier 只需等待一个副本响应,不会因为等待多个副本而放大延迟;
- 实现简单:读路径无需数据去重,省去多副本结果合并的复杂性与额外 CPU/内存开销;
- 负载均衡:zone sorter 在多个区域间随机打散请求顺序,避免查询全部打在单一区域副本上。
适用场景
- 多可用区部署的云原生环境(如 EKS/GKE/ACK 上跨 AZ 部署 Tempo 微服务形态);
- 需要保证 trace 查询在基础设施局部故障期间仍可用的生产集群;
- 追求读写路径低复杂度、同时具备跨域冗余能力的高吞吐 tracing 后端。
注意事项
instance_zone必须按故障域真实布局填写并保持一致,错误配置会导致所有副本落入同一区域,失去容灾意义;- 复制因子与仲裁关系是固定的(RF2 + quorum 1),不要尝试通过修改
ReplicationFactor等底层 ring 参数去改变该语义(pkg/ring/config.go 中ToRingConfig固定设置ReplicationFactor = 1,因为真正承担复制的语义由分区所有权与区域分配实现); - 部署新区域或下线区域时,注意
delete_inactive_partition_after(默认 13h)对分区状态转换的影响,避免分区长期滞留 INACTIVE。
七、进一步阅读
- 完整配置参考:frontend/docs/config-reference.md(其中包含
livestore.ring.instance_zone、querier.partition_ring.preferred_zone等字段的 YAML 示例); - live-store 配置与默认值:config.go;
- 分区 ring 配置:partition_ring.go;
- 查询端 zone sorter 实现:querier/partition_ring.go;
- ring 配置(
instance_zone、heartbeat_period、heartbeat_timeout):pkg/ring/config.go。
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考