- 时序数据库
- 后端
- 数据存储
- 可观测性
- 云原生
【免费下载链接】mimir
Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus.
Grafana Mimir 支持从 Prometheus、Cortex 乃至其他 Mimir 集群直接导入历史 TSDB 块(block),这是从存量监控系统向 Mimir 迁移数据时的核心能力之一。本文基于仓库中的配置文档与源码实现,完整讲解如何启用并配置该功能(全局与按租户两种粒度)、Mimir 在上传前/上传后分别执行哪些块校验、mimirtool backfill客户端与 compactor 上传 API 之间的完整交互流程,以及 Thanos 块不可上传、结果缓存失效、"过新"的块暂不可查这三类已知限制的原理与规避手段。
一、功能定位与总体说明
Grafana Mimir 支持上传来自 Prometheus、Cortex 或其他 Mimir 部署的历史 TSDB 块。需要特别注意的是:来自 Thanos 的块目前不支持直接上传(原因见本文"已知限制"一节,涉及 Thanos 外部标签)。
为了让块上传操作尽可能简单,Mimir 将客户端支持直接内置到了官方命令行工具mimirtool的backfill子命令中。该子命令的定位(源码描述)是"Upload Prometheus TSDB blocks to Grafana Mimir compactor",其定义见 backfill 命令注册。更完整的工具说明可参考仓库文档 mimirtool 手册。
块上传目前仍属于实验性功能(experimental),因此默认关闭。可以通过以下任一方式启用:
- CLI 标志:
-compactor.block-upload-enabled - 配置参数:
limits.compactor_block_upload_enabled
limits: # Enable TSDB block upload compactor_block_upload_enabled: true从源码看,这几个标志在 limits 定义 中注册,且每个都支持按租户覆盖(per-tenant override):
| 配置参数(limits.*) | CLI 标志 | 默认值 | 作用 |
|---|---|---|---|
compactor_block_upload_enabled | -compactor.block-upload-enabled | false | 是否对租户开放块上传 API |
compactor_block_upload_validation_enabled | -compactor.block-upload-validation-enabled | true | 上传完成后是否执行"整块"深度校验 |
compactor_block_upload_verify_chunks | -compactor.block-upload-verify-chunks | true | 深度校验时是否逐个校验 chunks(保留 index 校验) |
compactor_block_upload_max_block_size_bytes | -compactor.block-upload-max-block-size-bytes | 0(不限制) | 允许上传/校验的块大小上限(字节) |
对应的按租户查询入口为 Overrides 方法,如CompactorBlockUploadEnabled(tenantID)、CompactorBlockUploadMaxBlockSizeBytes(userID),这正是"全局默认 + 按租户覆盖"这一 Mimir 常规配置模式的体现。
二、按租户启用 TSDB 块上传
如果集群启用了多租户,除了用上一节的方式对所有租户统一开启之外,也可以只为指定租户开启块上传,推荐做法是通过 runtime configuration 设置按租户覆盖:
- 先启用 runtime configuration(
--runtime-config.mode=enabled等,详见上述文档); - 在
config-overrides.yaml中添加目标租户的覆盖项:
overrides: tenant1: compactor_block_upload_enabled: true从服务端实现看,每一次上传 API 请求都会经过租户校验:parseBlockUploadParameters 会解析 URL 中的块 ID 和请求上下文中的租户 ID,然后调用c.cfgProvider.CompactorBlockUploadEnabled(tenantID),若该租户未启用上传则直接拒绝:
if !c.cfgProvider.CompactorBlockUploadEnabled(tenantID) { return ulid.ULID{}, "", errors.New("block upload is disabled") }三、上传过程中的块校验规则
Mimir 对上传块采取"两步校验":先对meta.json做元数据检查,放行后才允许上传 index 与 chunks;上传完毕后再做更重的"整块校验"。
3.1 上传开始前的 meta.json 校验
在真正上传块数据之前,Mimir 会对meta.json文件执行以下检查(与文档 configure-tsdb-block-upload 所列规则一致):
- 仅支持 TSDB "v1" 块——这是 Prometheus v2、Grafana Mimir 与 Thanos 使用的格式;
MinTime/MaxTime非法的块被拒绝(负值,或MaxTime < MinTime);MinTime或MaxTime位于"未来"的块被拒绝;- 超出保留期(retention)的块被拒绝;
- 时间跨度超过最大 compaction range(
-compactor.block-ranges选项,最大档默认 24h)的块被拒绝; - 跨越最大 compaction range 边界的块被拒绝。例如最大 compaction range 为 24 小时时,前一天 23:00 开始、后一天 01:00 结束的块会被拒绝;
- 带 Thanos 降采样(downsampling)配置的块被拒绝;
- 超过
compactor_block_upload_max_block_size_bytes(按租户覆盖)的块被拒绝; - 带"外部标签"(external labels,Thanos 特性)的块被拒绝,部分 Mimir 专属标签例外允许。
这些规则的源码实现在 blockvalidation 包。其中CheckMeta函数(meta.go)覆盖如下检查点:
- 降采样检查:
meta.Thanos.Downsample.Resolution > 0时直接报block contains downsampled data; - 外部标签白名单:仅允许 Mimir 的 compactor shard ID 外部标签(且值必须可被
sharding.ParseShardIDLabelValue解析)以及若干已废弃的历史标签(会被清除),其他任何标签一律报unsupported external label: %s; - 文件路径与大小白名单:
meta.Thanos.Files中除meta.json外的文件,相对路径必须匹配正则^(index|chunks/\d{6})$(AllowedRelPath),且SizeBytes > 0; - 块大小上限:
CheckMaxBlockSize累加所有文件声明大小,超过MaxBlockSizeBytes时返回带限制值与大小的MaxBlockInvalidSizeError(<= 0表示不限制); - 版本检查:
meta.Version必须为block.TSDBVersion1,否则报version must be 1; - 时间检查:
MinTime < 0 || MaxTime < 0 || MaxTime < MinTime报invalid minTime/maxTime;任一时间戳大于当前时间(毫秒)报block time(s) greater than the present。
另外,保留期、时间跨度、跨边界这三项检查实现在 createBlockUpload:
// validate data is within the retention period retention := c.cfgProvider.CompactorBlocksRetentionPeriod(tenantID) if retention > 0 { threshold := time.Now().Add(-retention) if blockMaxTime.Before(threshold) { ... 422 ... } } blockDuration := blockMaxTime.Sub(blockMinTime) maxRange := c.compactorCfg.BlockRanges[len(c.compactorCfg.BlockRanges)-1] if blockDuration > maxRange { ... 422 ... } if blockMaxTime.After(blockMinTime.Truncate(maxRange).Add(maxRange)) { ... // 跨边界,422 }即在元数据阶段即被拒绝的块,会以400 Bad Request(参数错误)或422 Unprocessable Entity(块内容不符合要求)返回。
3.2 上传完成后的整块校验(full block validation)
index 和 chunks 上传完成后,Mimir 会执行额外校验,确认块结构完整(well-formed)且不会给 Mimir 的后续运行带来问题。相关开关(均为按租户覆盖参数):
- 通过
compactor_block_upload_validation_enabled可以整体关闭整块校验(关闭后 finish 请求直接标记块完成); - 若只想跳过昂贵的 chunks 逐块校验而保留 index 校验,则使用
compactor_block_upload_verify_chunks。
服务端对应的流程在 FinishBlockUpload:当CompactorBlockUploadValidationEnabled(tenantID)为真时,先检查并发数是否超过-compactor.max-block-upload-validation-concurrency(超出返回429 Too Many Requests),然后异步执行validateAndCompleteBlockUpload:
- 校验期间会在块目录下写入
validation.json心跳文件(每 1 分钟更新一次,validationHeartbeatInterval),超过 5 分钟(validationHeartbeatTimeout)未更新则视为 stale,允许重新开始校验; - 校验本身由 validateBlock 完成:先把块从对象存储下载到 compactor 本地临时目录(
-compactor.data-dir下upload*前缀的目录,进程重启时会由 cleanupLeftoverValidationDirectories 清理残留),再把临时元数据文件改名为正式的meta.json,最后调用blockvalidation.CheckBlockOnDisk,其CheckChunks选项由CompactorBlockUploadVerifyChunks(userID)决定; - 校验失败会把错误信息写入
validation.json并停留在failed状态;校验成功则进入markBlockComplete。
3.3 上传过程中的状态机与状态文件
整个上传过程通过块目录下的两个辅助文件驱动状态机(状态枚举见 block_upload.go):
| 状态文件 | 说明 |
|---|---|
uploading-meta.json | 上传"开始"时由 compactor 写入的元数据快照;正式的meta.json在整块校验通过后才写入 |
validation.json | 记录校验心跳时间戳(LastUpdate,毫秒)与错误信息(Error) |
由此可推导出块的上传状态:
meta.json存在 →complete;- 两个文件都不存在 → 块不存在(
404); - 仅
uploading-meta.json→uploading(上传中,允许继续传文件); uploading-meta.json+ 新鲜心跳的validation.json→validating(此时再传文件会收到400 block validation in progress);validation.json心跳超时(stale)→ 回退为uploading,校验可以重新发起;validation.json带Error→failed,且该块不可再重试(再次操作返回400 block validation failed)。
状态查询入口为 GetBlockUploadStateHandler,返回形如{"result": "complete"}或{"result": "failed", "error": "..."}的 JSON。
四、上传操作实战:mimirtool backfill 与 HTTP API
4.1 mimirtool backfill 命令
实际生产中不需要手写 HTTP 请求,直接用mimirtool backfill <block-dir>即可。从 命令定义 可见其主要参数(均可通过对应环境变量提供):
| 参数 | 默认值 | 说明 |
|---|---|---|
block-dir(位置参数,可多个) | 必填 | 要上传的块所在目录,目录名即块 ULID |
--address | 空(必填,--dry-run除外) | Mimir 集群地址 |
--id | 空(必填,--dry-run除外) | 租户 ID,用于X-Scope-OrgID请求头 |
--user/--key | 空 | Basic Auth 用户名/密码(未提供--user时用--id作用户名) |
--extra-headers | 空 | 附加请求头,header=value形式 |
--tls-ca-path/--tls-cert-path/--tls-key-path/--tls-insecure-skip-verify | — | mTLS 配置 |
--sleep-time | 20s | 上传完文件后轮询块状态的间隔 |
--verify | false | 上传前先本地校验块(实验特性,当前默认关闭) |
--dry-run | false | 只校验不上传,全部通过时退出码 0 |
--fail-fast | true | 校验发现首个失败即中止 |
--deep-verification | true | 高深度校验,包括逐 chunk 的 CRC32 遍历(较慢) |
--single-block-per-day | false | 校验时强制每个 UTC 日最多一个块;否则允许同日多块但不得重叠;无论哪种,块都不允许跨两个 UTC 日 |
--verify-concurrency | 0(取min(GOMAXPROCS, 4)) | 并行校验的块数,1 为串行 |
典型的本地校验用法(不上传,先体检):
mimirtool backfill /path/to/blocks/ --dry-run --no-fail-fast4.2 客户端与 compactor 的交互流程
BackfillWithOptions 与 backfillBlock 实现了完整的上传编排:
- (可选)先运行本地校验器,任何块校验失败则不发出任何上传请求(
--dry-run时校验通过即直接返回); - 读取本地块目录中的
meta.json,并按目录实际内容重建thanos.files文件列表(GetBlockMeta 会用文件系统的真实大小覆盖/补齐文件清单,且强制要求version == 1); POST /api/v1/upload/block/{block}/start,请求体为 meta 的 JSON(服务端 StartBlockUpload 限制 meta 请求体最大 1 MiB,然后执行 3.1 节的元数据校验,通过后写入uploading-meta.json);- 对 meta 中除
meta.json外的每个文件(index、chunks/000001…),POST /api/v1/upload/block/{block}/files?path={relPath}。服务端 UploadBlockFile 会核对:块处于上传中状态、路径匹配白名单、文件确实在thanos.files中声明、声明大小与实际ContentLength一致,最后直接写入租户桶的{blockID}/{relPath}; POST /api/v1/upload/block/{block}/finish。若命中并发校验上限收到429,客户端按--sleep-time退避重试;- 轮询
GET /api/v1/upload/block/{block}/check,直到状态为complete(成功)、failed(携带错误原因,如block validation failed: ...)或上下文取消; - 汇总输出
succeeded / already_exists / failed计数;对已存在的块(服务端返回409 Conflict)计入already_exists而不视为失败。
4.3 上传 API 路由一览
上述端点在 API 路由注册处 统一定义:
| 方法 | 路径 | 用途 |
|---|---|---|
POST | /api/v1/upload/block/{block}/start | 提交 meta.json,开始上传 |
POST | /api/v1/upload/block/{block}/files?path=... | 上传块内单个文件 |
POST | /api/v1/upload/block/{block}/finish | 结束上传并触发校验 |
GET | /api/v1/upload/block/{block}/check | 查询上传/校验状态 |
所有请求都需要租户头(X-Scope-OrgID或等效认证),且该租户必须已启用块上传。
五、TSDB 块上传的已知限制
以下三类限制必须在使用前了解清楚,它们均来自文档与源码可确认的事实。
5.1 Thanos 块无法直接上传
Thanos 块的元数据中带有 Mimir 不支持的外部标签(external labels),因此无法上传。从源码看,CheckMeta 对外部标签执行严格白名单:凡不属于 Mimir 允许集合的标签一律以unsupported external label: %s拒绝,而 Thanos 块普遍携带thanos.ruler等自有标签,因此整块被拒。关于从 Thanos/Prometheus 导入的更多限制与已有绕行方案,可参考仓库文档 Migrating from Thanos or Prometheus to Grafana Mimir。
5.2 上传后需要冲刷结果缓存(results cache)
Mimir 会把早于 10 分钟(可通过-query-frontend.max-cache-freshness配置)的采样区间查询结果缓存在 range query 结果缓存中。上传新块后,同一查询区间的数据已经变化,缓存中的旧结果就会"错误"。应对方式:
- 由 Mimir 运维人员手动冲刷结果缓存;
- 或把结果缓存 TTL 从默认 7 天调短,例如用
-query-frontend.results-cache-ttl命令行列选项(或按租户覆盖)设为 6 小时,这样最坏情况下 6 小时内查询结果就会基于回填后的数据。
对应的租户级接口(如MaxCacheFreshness、ResultsCacheTTL)定义在 querymiddleware/limits.go,说明这两项参数同样支持 per-tenant override。
5.3 "太新"的块在一段时间内查不到
Querier 收到[start, end]查询区间后,会依据该区间与-querier.query-store-after的关系决定从对象存储、ingester 还是两者同时读取数据。假设-querier.query-store-after为12h:查询[now-13h, now]会读存储,而[now-5h, now]只读 ingester。若用户上传了时间范围落在"新鲜窗口"内的块,querier 按配置只会向 ingester 查询该区间的"实时"数据,刚上传的块在这段时间内不会被查询命中,需要等到查询区间整体滑出query-store-after窗口后才可见。这一分区逻辑可参考 frontend v2 的 QueryStoreAfter 处理。
六、小结
- 启用方式:全局用
-compactor.block-upload-enabled/limits.compactor_block_upload_enabled,多租户场景推荐通过 runtime configuration 按租户覆盖compactor_block_upload_enabled; - 上传入口:
mimirtool backfill命令,底层走 compactor 的/api/v1/upload/block/{block}/start|files|finish|check四个 API; - 校验分层:meta.json 元数据检查(版本、时间、保留期、24h 边界、外部标签、大小上限)→ 整块磁盘校验(可用
compactor_block_upload_validation_enabled/compactor_block_upload_verify_chunks按租户调节); - 使用前注意三个限制:Thanos 块不可上传(外部标签白名单所致)、上传后要冲刷或缩短 TTL 的结果缓存、以及受
-querier.query-store-after影响"太新"的块延迟可见。
- 时序数据库
- 后端
- 数据存储
- 可观测性
- 云原生
【免费下载链接】mimir
Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus.
相关推荐
Grafana Mimir 开发调试:使用 upload-block 脚本将真实数据块上传到本地 Docker Compose 环境
Grafana Mimir 开发调试:使用 upload block 脚本将真实数据块上传到本地 Docker Compose 环境 本篇技术指南以仓库内 de
时序数据库后端数据存储可观测性云原生Grafana Mimir 运行时配置(Runtime Configuration)详解:不重启修改租户限制与实例限制
Grafana Mimir 运行时配置(Runtime Configuration)详解:不重启修改租户限制与实例限制 Grafana Mimir 的运行时配置
时序数据库后端数据存储可观测性云原生Grafana Mimir 配置体系实战:YAML 文件、CLI Flags、common 继承与启动前校验
Grafana Mimir 配置体系实战:YAML 文件、CLI Flags、common 继承与启动前校验 Grafana Mimir 的所有行为都通过 YA
时序数据库后端数据存储可观测性云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考