ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Grafana Mimir 术语表深度解析:Blocks storage、Hash ring、WAL 等核心概念全解

Grafana Mimir 术语表深度解析:Blocks storage、Hash ring、WAL 等核心概念全解
  • 时序数据库
  • 后端
  • 数据存储
  • 可观测性
  • 云原生

【免费下载链接】mimir

Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus.

项目地址:https://gitcode.com/gh_mirrors/mimir/mimir
点击查看免费下载

Grafana Mimir 是一套为 Prometheus 提供水平可扩展、高可用、多租户长期存储的时序数据库系统。本文以官方 Glossary(术语表)为骨架,逐条拆解 Blocks storage、Chunk、Churn、Hash ring、Memberlist、HA tracker、WAL 等核心术语的准确定义,并结合仓库源码与配置项给出底层实现依据,帮助读者快速建立对 Mimir 数据模型与分布式架构的整体认知。

为什么需要一份术语表

Grafana Mimir 的文档、配置和源码中频繁出现一系列高度领域化的术语,例如block、chunk、ring、WAL、tenant。这些术语之间往往存在衍生与互指关系(例如 "Ring" 指向 "Hash ring","Org" 与 "User" 都指向 "Tenant")。对于刚接触 Mimir 的开发者而言,准确理解这些概念是读懂架构图、排查分布式读写问题、解读告警与日志的前提。

本文整理自 Mimir 官方 Glossary(见 docs/sources/mimir/references/glossary.md),并对每个术语补充了当前仓库中可验证的源码与配置依据,力求"一词一义、一词一证"。

Blocks storage(块存储)

Blocks storage 是 Mimir 基于 Prometheus TSDB 构建的存储引擎。Mimir 将时序数据以 Prometheus 原生 TSDB 的 block(数据块)形式写入对象存储,支持的后端包括:

  • AWS S3
  • Google Cloud Storage(GCS)
  • Azure Blob Storage
  • OpenStack Object Storage(Swift)

从源码结构看,Mimir 的 ingest 侧直接依赖github.com/prometheus/prometheus/tsdb(见 pkg/ingester/ingester.go 第 33 行的 import),而对象存储相关的 bucket 抽象集中在 pkg/storage/bucket 目录,存储配置项则定义在 pkg/storage/tsdb/config.go。这意味着 Mimir 并没有另起炉灶发明存储格式,而是复用 Prometheus 久经生产验证的 block 格式,将其从"单机本地磁盘"扩展到"分布式对象存储"。

Chunk(块)

Chunk 是包含一条 series(序列)的编码后时间戳-值(timestamp-value)对的对象。它是比 block 更细粒度的数据组织单位:

  • block是 TSDB 落盘/上传对象存储的目录级单元,包含元数据、索引与多个 chunk 文件;
  • chunk则是 block 内部按序列组织、经过编码压缩的时间戳-值批量数据。

写入路径上,ingester 先在内存 TSDB head 中积累 chunk,待达到压缩条件后固化到 block 中;查询时 store-gateway 负责从 block 中读取并解压相关 chunk。因此 chunk 编码格式(例如 float chunk encoding)甚至被作为租户级限流/覆盖项暴露出来,详见 pkg/util/validation/exporter/exporter.go 中的float_chunk_encoding相关逻辑。

Churn(流失/序列更替)

Churn 描述 series 进入 idle(空闲)状态的频率。一条 series 在被监控目标停止导出后即变为 idle,典型场景是被监控的进程或节点被终止。

Churn 之所以重要,是因为它直接决定了:

  • 时序数据量:高 churn 意味着需要跟踪、索引和查询的 series 数量增长更快;
  • 内存压力:ingester 需要为不断新增的 series 维护索引与样本缓冲区;
  • 存储成本:store-gateway 需要加载更多 block 元数据来响应查询。

Mimir 通过 pkg/ingester/activeseries 等模块跟踪活跃 series,并依靠 TSDB head 的闲置压缩(见下文 Flushing)及时收敛失效数据的内存占用。

Component(组件)

Grafana Mimir 由多个组件(component)组成,每个组件为系统提供一项特定功能。官方术语表列出的核心组件包括:

组件职责定位仓库对应目录
Compactor压缩、去重、合并存储桶中的 blockpkg/compactor
Distributor校验数据、对写入进行分片与复制pkg/distributor
Ingester接收写入,在内存中积累数据并周期落盘pkg/ingester
Query-frontend查询前端,负责拆分、缓存与排队查询pkg/frontend
Query-scheduler调度查询请求到 query-frontendpkg/scheduler
Store-gateway提供对长期存储中 block 的查询访问pkg/storegateway
Alertmanager(可选)多租户告警管理pkg/alertmanager
Ruler(可选)周期评估告警/记录规则pkg/ruler

组件既可按微服务模式独立部署,也可按单进程模式(monolithic mode)合并运行,开发环境示例见 development/mimir-monolithic-mode 下的 docker-compose 配置。

Flushing(刷盘)

Flushing 是 ingester 将时序数据从内存卸载(offload)并写入长期存储的操作。它是 Mimir 写入路径上"内存 → 对象存储"的关键转换环节。

与 Flushing 相关的配置集中在 pkg/storage/tsdb/config.go 的 TSDBConfig 中:

  • blocks-storage.tsdb.head-compaction-idle-timeout(默认1h):TSDB head 闲置该时长后触发压缩(compaction),并附加最多 25% 的抖动以避免所有 ingester 同时压缩;
  • blocks-storage.tsdb.flush-blocks-on-shutdown(默认false):关闭时是否将未完成的 block 刷到存储;若为false,重启后会复用未完成的 block 而非立即上传;
  • blocks-storage.tsdb.wal-compression-enabled(默认false):是否对 TSDB WAL 进行压缩(详见 WAL 一节)。

在 pkg/ingester/ingester.go 中,ingester 的 lifecycler 会携带cfg.BlocksStorageConfig.TSDB.FlushBlocksOnShutdown与i.Flush回调,从而在实例退出时协调刷盘动作,保证数据不丢失。

Gossip(流言协议)

Gossip 是一种让组件之间无需集中式 key-value store 即可协调的协议。在 Mimir 中,Gossip 被用于:

  • 集群成员管理;
  • 节点故障检测;
  • hash ring 状态在节点间的传播。

Mimir 使用的 Gossip 协议具体实现是Memberlist(见下节),它允许在不部署 Consul/etcd 的情况下,仅凭节点间相互通信维护一致的集群状态视图,这对单二进制部署尤其友好。

HA tracker(高可用跟踪器)

HA tracker 是 Grafana Mimir distributor 的一项功能,用于对两台及以上、配置为抓取相同目标的 Prometheus 服务器所上报的时序进行去重。它是 Prometheus 高可用(HA)双写场景的核心组件。

HA tracker 的实现位于 pkg/distributor/ha_tracker.go,关键配置与行为:

  • 通过distributor.ha-tracker.enable(对应HATrackerConfig.EnableHATracker)启用;
  • 需要 Prometheus 端附加 HA 专用标签(cluster 与 replica);
  • 集群内部通过选举(election)决定当前接受哪个 replica 的样本,其他 replica 的样本被丢弃;
  • 选出的 replica 状态通过elected_replica_status等指标对外暴露,其中enable-elected-replica-metric默认关闭以避免高基数指标(见 pkg/distributor/ha_tracker.go 中EnableElectedReplicaMetric的注释)。

值得注意的默认值:HA tracker 的 KVStore 后端在未显式配置时默认设置为memberlist(见HATrackerConfig.RegisterFlags中 "Set the default to memberlist before registering flags" 的注释),支持的取值包括 consul、etcd、inmemory、memberlist、multi,其中 memberlist 为官方推荐。

Hash ring(哈希环)

Hash ring 是 Mimir 用于分片(sharding)、复制(replication)与服务发现(service discovery)的分布式数据结构。组件通过 key-value store 或 Gossip 共享 hash ring 状态。

底层机制(依据 vendor/github.com/grafana/dskit/ring 的 dskit ring 实现):

  1. Token 分配:每个实例在环上认领若干 token(默认通过RandomTokenGenerator生成,见 basic_lifecycler.go 的注释),token 将环划分为多个区间;
  2. 键到实例映射:对每个数据键(如 series 的 tenant ID 与 label 集合)计算哈希得到 key,再从 key 位置顺时针查找 token,findInstancesForKey(见 ring.go)依次收集 token 对应的实例形成副本集合;
  3. 复制与容错:ReplicationStrategy.Filter(见 replication_strategy.go)基于minSuccess = (replicationFactor / 2) + 1的多数派(quorum)要求,过滤心跳超时的病态实例并计算可容忍的最大失败数MaxErrors;
  4. 心跳健康检查:实例通过BasicLifecycler定期向 KV store 写心跳,读侧用HeartbeatTimeout判定实例是否健康;
  5. 区域感知(zone awareness):启用后,副本集合会尽量跨不同可用区(availability zone)分布,findInstancesForKey中按 zone 跟踪已查找/已命中实例数(见 ring.go);
  6. 分片减容(Shuffle sharding):ShuffleShard(见 ring.go)为每个租户从完整环中挑选固定大小的子环,减少故障爆炸半径。

写入路径上,distributor 对每条 series 计算tokenForLabels(userID, labels)(见 pkg/distributor/distributor.go),通过 hash ring 确定由哪些 ingester 接收该 series。

Key-value store(键值存储)

Key-value store 是一种将键与值关联的数据库。在 Mimir 中,它是 hash ring 状态与 HA tracker 选举状态的共享后端,支持 consul、etcd、inmemory、memberlist、multi 等后端(multi 表示多个后端组合)。

选择要点:

  • memberlist:去中心化,基于 Gossip,无需额外基础设施,适合中小规模与单二进制部署;
  • consul / etcd:集中式 KV store,适合大规模集群或已有此类基础设施的环境。

成员管理与 Gossip 协议的具体实现来自 dskit 库的 vendor/github.com/grafana/dskit/kv/memberlist,其中KVInitService(见 kv_init_service.go)负责在首次调用时初始化并启动 memberlist KV,若 KV 服务失败会将错误上报给上层服务管理框架。

Memberlist

Memberlist 使用 Gossip 管理集群成员关系与成员故障检测。它源自 HashiCorp 的 memberlist 库,被 dskit 封装为可承载 KV 数据的广播与合并机制(见 vendor/github.com/grafana/dskit/kv/memberlist/memberlist_client.go 与 broadcast.go)。

在 Mimir 中,memberlist 承担两类角色:

  1. KV 后端:作为 hash ring、HA tracker 等共享状态的存储与传播通道;
  2. 集群通信层:节点间通过 TCP/UDP 相互探测存活状态,当节点加入或离开时,其他节点通过 Gossip 在秒级内感知变化。

Mimir 的成员管理配置集中在-memberlist.*前缀下(见 pkg/mimir/mimir.go 中的默认值,如memberlist.packet-dial-timeout: 500ms、memberlist.max-concurrent-writes: 5等),单二进制多实例部署可直接借助 memberlist 完成自动发现,无需额外依赖。

Org / User / Tenant

Org(Organisation)与 User 均指代同一个概念:Tenant(租户)。在 Mimir 中,tenant 与 Prometheus/Cortex 生态中的 "Org"、"User" 是历史命名差异,语义完全相同。

Ring

Ring 即 Hash ring,详见上文"Hash ring"小节。

Sample(样本)

Sample 是时间序列中单个带时间戳的值。以官方术语表给出的序列node_cpu_seconds_total{instance="10.0.0.1",mode="system"}为例,其样本流可能如下:

# Display format: <value> @<timestamp> 11775 @1603812134 11790 @1603812149 11805 @1603812164 11819 @1603812179 11834 @1603812194

每个样本由一个值(如11775)和一个 Unix 秒级时间戳(如1603812134)构成,是 Mimir 存储与查询处理的最小数据单元。

Series(序列)

Series 是隶属于同一指标(metric)、且具有相同标签键值对集合的样本流。给定单一指标node_cpu_seconds_total,可以存在多条 series,每条 series 由指标名与唯一标签组合唯一标识:

node_cpu_seconds_total{instance="10.0.0.1",mode="system"} node_cpu_seconds_total{instance="10.0.0.1",mode="user"} node_cpu_seconds_total{instance="10.0.0.2",mode="system"} node_cpu_seconds_total{instance="10.0.0.2",mode="user"}

series 是 Mimir 中标签索引、分片(sharding)、去重(deduplication)与计费(cost attribution)的基本单位。Mimir 的连续测试(continuous test)模块会在运行时写入并查询固定 series 集合以验证端到端正确性,相关实现见 pkg/continuoustest。

Tenant(租户)

Tenant 是写入并查询 Mimir 的一组 series 的所有者。Mimir 对不同租户的 series 与告警进行隔离。多租户是 Mimir 的核心能力之一:

  • 数据隔离:每个租户的数据在存储桶中以租户 ID 为前缀分目录存放;
  • 限流与配额:每个租户可配置独立的 series 数量上限、活跃 series 上限、查询超时等限制(见 pkg/util/validation 与 overrides exporter 的 per-tenant 指标导出逻辑);
  • 认证授权:租户通过请求中的身份信息(如X-Scope-OrgID头部或认证中间件)被识别,Mimir 的 tenant 解析逻辑见 pkg/util/tenant(含tenant.TenantIDs等辅助函数)。

Time series(时间序列)

Time series 即 Series,二者等价,详见上文"Series"小节。

Write-ahead log(WAL,预写日志)

WAL 是 ingester 存储在磁盘上的追加式(append-only)日志,用于在进程重启后恢复其内存状态。它的设计目标与 Prometheus TSDB WAL 一致:

  1. 写入路径先把样本追加到 WAL,再更新内存中的 TSDB head;
  2. 若 ingester 进程崩溃或重启,内存数据丢失后通过回放(replay)WAL 恢复;
  3. WAL 中的记录可压缩(blocks-storage.tsdb.wal-compression-enabled,默认false),以减少磁盘占用与回放开销。

相关源码佐证:

  • ingester 启动路径中明确"在回放 WAL 期间不施加内存 series 限制",见 pkg/ingester/ingester_http.go 的注释;
  • WAL 回放并发度是可测试的配置行为,测试用例见 pkg/ingester/ingester_test.go 中expectedTSDBWALReplayConcurrency相关断言;
  • 因此,"重启不丢已确认数据"的持久性保障由 WAL + Flushing(落块)共同承担。

术语关系速查

术语关联关系
Org / User→ Tenant
Ring→ Hash ring
Time series→ Series
Memberlist基于 Gossip,可充当 Key-value store 后端
Hash ring依赖 Key-value store 或 Gossip 共享状态
HA tracker依赖 Key-value store(推荐 memberlist)记录选举状态
Block / ChunkChunk 属于 Block 内部更细粒度的数据组织单元

结语

这份术语表覆盖了 Mimir 从数据模型(Sample/Series/Chunk/Block)、写入与持久化(WAL/Flushing)、分布式协调(Hash ring/Key-value store/Gossip/Memberlist)到多租户(Tenant)与高可用(HA tracker)的完整技术栈。建议读者在阅读架构文档、编写配置或排查告警时,随时回到本文核对术语含义;结合上文给出的源码与配置路径,可以进一步深入 Mimir 的实现细节。相关概念在官方文档体系中的完整阐述,可从 docs/sources/mimir/references/glossary.md 出发继续查阅对应的架构专题文档。

  • 时序数据库
  • 后端
  • 数据存储
  • 可观测性
  • 云原生

【免费下载链接】mimir

Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus.

项目地址:https://gitcode.com/gh_mirrors/mimir/mimir
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进