首页
/ Prometheus 存储层深度解析:本地 TSDB 布局、压缩策略、远程存储集成与数据回填

Prometheus 存储层深度解析:本地 TSDB 布局、压缩策略、远程存储集成与数据回填

2026-09-06 10:21:27作者:翟萌耘Ralph

本文以 docs/storage.md 为骨架,结合当前仓库源码,系统讲解 Prometheus 本地时序数据库(TSDB)的磁盘布局、WAL 机制、压缩与保留策略、远程读/写集成,以及基于 OpenMetrics 与 Recording Rules 的数据回填方案。读完后你可以独立完成 TSDB 容量规划、保留策略配置、损坏恢复判断,以及跨系统数据迁移的完整实操。

Prometheus 远程读/写集成架构

一、本地存储:TSDB 的磁盘布局

Prometheus 的本地时序数据库将数据以自定义的高效格式存储在本机磁盘上。理解其物理布局是后续容量规划与故障恢复的基础。

1.1 两小时 Block 的结构

摄入的样本(sample)会被分组为两小时(2h)的 Block。每个 Block 是一个目录,包含:

  • chunks/ 子目录:该时间窗口内所有时间序列的样本数据;
  • meta.json:块元数据;
  • index 文件:将指标名与标签映射到 chunks 目录中的时间序列;
  • tombstones:删除记录文件。

chunks 目录内的样本被组织为一个或多个 segment 文件,每个默认最大 512 MB。当通过 API 删除时间序列时,删除操作并不会立即从 chunk 段中移除数据,而是先写入独立的 tombstone 文件,由后续压缩(compaction)统一清理——这是典型的"标记删除 + 后台重写"设计。

当前正在写入的 Block(Head)常驻内存,尚未完全落盘。它依靠**预写日志(WAL)**抵御崩溃:重启时可重放 WAL 恢复数据。WAL 文件存放在 wal 目录中,segment 为 128MB。由于 WAL 保存的是尚未压缩的原始数据,其体积显著大于常规 block 文件;Prometheus 至少保留 3 个 WAL 文件,高流量实例可能保留更多,以保证至少覆盖两小时的原始数据。

一个典型的 Prometheus 数据目录如下(引自 docs/storage.md):

./data
├── 01BKGV7JBM69T2G1BGBGM6KB12
│   └── meta.json
├── 01BKGTZQ1SYQJTR4PB43C8PD98
│   ├── chunks
│   │   └── 000001
│   ├── tombstones
│   ├── index
│   └── meta.json
├── 01BKGTZQ1HHWHV8FBJXW1Y3W0K
│   └── meta.json
├── 01BKGV7JC0RY8A6MACW02A2PJD
│   ├── chunks
│   │   └── 000001
│   ├── tombstones
│   ├── index
│   └── meta.json
├── chunks_head
│   └── 000001
└── wal
    ├── 000000002
    └── checkpoint.00000001
       └── 00000000

目录名是 ULID 格式的块标识符;chunks_head/ 是内存 Head 中已 m-map 落盘的 chunk;checkpoint.* 是 WAL 检查点,用于截断旧 WAL 段。

文件级别的格式细节(index、chunks、tombstones、WAL 的二进制结构)可参阅仓库中的 TSDB 格式文档,其下分为 index.mdchunks.mdhead_chunks.mdtombstones.mdwal.mdmemory_snapshot.md

1.2 单节点局限与备份建议

本地存储的限制是没有集群化与复制,不能随意扩展,也难以抵御磁盘或节点故障,应像管理任何单节点数据库一样管理它;在合理架构下,本地存储仍可保留多年数据。

  • 备份推荐使用 Snapshot:直接拷贝数据目录而不走 snapshot,可能丢失自上一个 TSDB block 创建以来(通常每 2 小时一次)的最新数据,覆盖最近约 3 小时的样本。备份/恢复时排除 WAL 文件(chunks_head/wal/wbl/ 目录)可以保证数据一致性,代价是丢失 WAL 所覆盖的时间范围。Snapshot 的使用方式见 查询 API 文档的 snapshot 章节
  • 或者通过 remote read/write API 使用外部存储(见下文第四节),但需要针对持久性、性能与效率仔细评估。

二、压缩(Compaction)与保留策略

2.1 后台压缩如何工作

初始的两小时 block 最终会在后台被压缩为更长的 block。压缩会创建跨度最多为**保留时间的 10% 或 31 天(取较小者)**的新 block。由于源块与新压缩块必须同时在磁盘上共存,磁盘占用会短暂超过 storage.tsdb.retention.size 的设定值;当下一次保留清理删除源块后,多余空间即被释放。

这一机制在源码中可以印证:主程序在初始化时会根据保留时间计算最大块时长上限,即 maxBlockDuration = retentionDuration / 10(见 cmd/prometheus/main.go 中 retention 解析段落)。

2.2 关键配置项

本地存储的核心配置项及其含义(继承自 docs/storage.md,并结合当前仓库源码更新):

配置 说明 默认值
--storage.tsdb.path Prometheus 写入数据库的基路径 data/
--storage.tsdb.retention.time 样本保留时长。与 size 都未设置时默认 15d。支持单位:y, w, d, h, m, s, ms 15d
--storage.tsdb.retention.size 存储块的最大字节数,最旧数据优先删除。支持单位:B, KB, MB, GB, TB, PB, EB(2 的幂,1KB=1024B),如 512MB0 表示禁用。只有持久化 block 会被删除以满足该限制,但 WAL 与 m-map chunk 会计入总大小,因此磁盘最低需求 = wal(WAL+Checkpoint)与 chunks_head 峰值之和(每 2 小时出现一次峰值) 0(禁用)
--storage.tsdb.wal-compression 启用 WAL 压缩。视数据而定,WAL 体积大约可减半,额外 CPU 开销很小。2.11.0 引入,2.20.0 起默认开启;一旦启用,降级到 2.11.0 之前的版本需要删除 WAL 按版本默认

重要现状说明(以当前仓库为准):在 cmd/prometheus/main.go 中,storage.tsdb.retention.timestorage.tsdb.retention.size 两个命令行 flag 已标记为 [DEPRECATED],官方建议改用配置文件中的 storage.tsdb.retention.time / storage.tsdb.retention.size 字段;配置文件顶层的 storage: tsdb: 段落(见 configuration.md 存储配置storage 部分)同时新增了按容量百分比保留的能力(storage.tsdb.retention.percentage 指定后,size 限制会被忽略,见 cmd/prometheus/main.go 中的告警逻辑)。

此外,从 flag 定义可以看出本地存储还有若干与本篇主题相关的高级开关,例如:

  • --storage.tsdb.wal-segment-size(10MB–256MB 之间):调整 WAL 段大小;
  • --storage.tsdb.allow-overlapping-compaction:是否允许重叠块的垂直压缩;
  • --storage.tsdb.block-reload-interval:检查新增/移除 block 的间隔,手动回填或删除 block 后需等待至多该时长才生效——这与第五、六节手动搬移 block 的操作直接相关。

2.3 容量规划公式

Prometheus 平均每个样本只占 1–2 字节(得益于系列内样本压缩,尤其是 XOR 编码),因此容量规划可用近似公式:

needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample

若要降低样本摄入速率,可以:减少抓取的时间序列数量(更少的 target,或每个 target 更少的 series),或增大抓取间隔。其中减少序列数量往往更有效,因为同一序列内的样本会被压缩。

2.4 保留大小右-sizing(Right-Sizing)

若使用 storage.tsdb.retention.size 设置容量上限,应使其相对于为 Prometheus 分配的磁盘留出缓冲,确保旧数据在磁盘写满之前先被清除。官方建议:

保留大小最多设为已分配磁盘空间的 80–85%。剩余 15–20% 的缓冲用于覆盖压缩进行中所需的临时空间(源块与新压缩块同时驻留磁盘,见上文 2.1)。

2.5 过期清理与损坏恢复

  • 若同时指定时间与大小两种保留策略,先触发者生效
  • 过期 block 的清理在后台进行,最长可能需要两小时才会移除过期块,且块必须完全过期才会被删除;
  • 若本地存储损坏到 Prometheus 无法启动:先备份存储目录,再从备份恢复损坏的 block 目录;没有备份时最后手段是删除损坏文件(逐个 block 目录或 WAL 文件),代价是丢失相应时间范围的数据;
  • CAUTION:非 POSIX 文件系统不受支持,可能造成不可恢复损坏;NFS(包括 AWS EFS)不受支持——NFS 理论上可以符合 POSIX,但多数实现并不。强烈建议使用本地文件系统。

三、远程存储集成:Remote Read / Write

本地存储受限于单节点的可扩展性与持久性。Prometheus 没有在自身内部解决集群化存储,而是提供一组接口以集成外部存储系统。

3.1 四种集成方式

Prometheus 与远程存储的集成有四种形态:

  1. 将摄入的样本以 Remote Write 格式写往远程 URL;
  2. Remote Write 格式接收其他客户端发来的样本;
  3. Remote Read 格式从远程 URL 读回样本数据;
  4. Remote Read 格式向客户端返回其请求的样本数据。

读/写协议均为 snappy 压缩的 Protocol Buffers 编码,传输于 HTTP 之上。协议定义见 prompb/remote.protoWriteRequest 携带 repeated TimeSeries 与 metadata(L22-L28);ReadRequest 携带一组 Query(每个 query 含 start/end 时间戳与 label matchers,L31-L72),并支持 SAMPLESSTREAMED_XOR_CHUNKS 两种响应类型协商——流式 XOR 响应直接以 XOR 编码的 chunk 逐序列传输,省去解码-再编码开销。

读协议目前不被视为稳定的 API;写协议则有 1.0 稳定版与 2.0 实验版两代规范,Prometheus server 均支持。

3.2 读路径的固有限制

读路径上,Prometheus 仅从远端按"标签选择器集合 + 时间范围"取回原始序列数据,所有 PromQL 评估仍发生在 Prometheus 自身。这意味着 remote read 查询存在扩展性上限:所有必要数据必须先加载进查询端 Prometheus 再处理。官方认为完全分布式的 PromQL 评估在现阶段不可行。

3.3 让 Prometheus 自身充当 Remote 服务端

Prometheus 同时提供这两种协议的服务端实现:

  • Remote write 接收端:需设置 --web.enable-remote-write-receiver 命令行 flag 启用,端点为 /api/v1/write。flag 定义见 cmd/prometheus/main.go;若未启用即访问该端点,会返回 404 并提示 "remote write receiver needs to be enabled with --web.enable-remote-write-receiver"(见 web/api/v1/api.go)。同一文件中还可通过 --web.remote-write-receiver.accepted-protobuf-messages 控制接收时接受的 protobuf 消息类型。
  • Remote read 端点/api/v1/read,使用方式见 Remote Read API 文档

作为客户端发起 remote write / remote read 的完整配置(remote_write:remote_read: 配置块,含队列参数、重试与 relabel 等)见 配置文档的 remote_write 章节remote_read 章节。集成生态的具体列表以官方 Integrations 文档为准。

四、从 OpenMetrics 格式回填数据(promtool tsdb create-blocks-from openmetrics)

4.1 适用场景与安全性约束

当需要从 OpenMetrics 格式数据在 TSDB 中创建 block 时使用 backfilling。注意:回填最近 3 小时的数据是不安全的——该时间范围可能与仍在变更的当前 Head block 重叠。

回填会创建新的 TSDB block,每个含两小时数据,从而限制建块时的内存需求;后续把 2h 块压缩为更大的块由 Prometheus server 自行完成。典型用例是把其他监控系统或时序数据库的数据迁入 Prometheus:先将源数据转换为 OpenMetrics 格式(backfill 的输入格式)。

限制:原生直方图(native histograms)与 staleness 标记不被支持,因为 OpenMetrics 格式无法表达它们。

4.2 使用方式

通过 promtool 使用,实现见 cmd/promtool/backfill.go。输出目录默认 ./data/,可用子命令的可选参数指定:

promtool tsdb create-blocks-from openmetrics <input file> [<output directory>]

块创建完成后,将输出目录中的 block 移入 Prometheus 数据目录。对于 v2.38 及更早版本,若与现有 block 存在时间重叠,需设置 --storage.tsdb.allow-overlapping-blocks(当前版本已默认允许重叠块;且注意移动 block 后需等待 --storage.tsdb.block-reload-interval 间隔内被重新加载)。任何回填数据都受 Prometheus server 配置的保留策略(时间或大小)约束,超出部分会被正常清理。

4.3 更长的块时长(--max-block-duration)

默认情况下 promtool 使用默认块时长(2h),这是最通用、最正确的行为。但回填大时间范围的数据时,更大的块时长可以加快回填并避免 TSDB 后续额外压缩。--max-block-duration 允许用户配置块的最大时长,工具会自动选取不超过该值且合适的块时长。

但大块的代价同样存在:

  • 基于时间的保留策略:只要块内(可能很大的块)有一个样本仍在保留期内,就必须保留整个块;
  • 基于大小的保留策略:哪怕只是轻微超出大小上限,整个块也会被删除。

因此,用更少(更大)的块做回填必须谨慎,不建议在任何生产实例上这样做

五、为 Recording Rules 回填历史数据

5.1 动机

新建的 recording rule 没有历史数据——规则数据只从创建时刻起存在。promtool 提供了补建历史 recording rule 数据的能力。

5.2 使用方式

查看全部选项:

$ promtool tsdb create-blocks-from rules --help

示例(--start / --end 为 Unix 秒级时间戳):

$ promtool tsdb create-blocks-from rules \
    --start 1617079873 \
    --end 1617097873 \
    --url http://mypromserver.com:9090 \
    rules.yaml rules2.yaml

要点:

  • 提供的 recording rule 文件应是标准的 Prometheus 规则文件;
  • 输出是一个包含所有规则历史数据 block 的目录,默认 data/
  • 要使用该数据,需将 block 移入运行中 Prometheus 实例的 storage.tsdb.path(v2.38 及以下需启用 --storage.tsdb.allow-overlapping-blocks)。移入后,新 block 会在下一次压缩时与现有块合并。

5.3 已知限制

  • 多次以重叠的 start/end 时间运行规则回填器,每次都会创建含相同数据的 block(重复数据);
  • 规则文件中的所有规则都会被求值
  • 若规则文件中设置了 interval,其优先级高于回填命令的 eval-interval flag;
  • 规则文件中的 Alerts 目前被忽略
  • 同一 group 内的规则看不到前一个规则的结果,即不支持回填引用其他被回填规则的规则。变通方法:多次回填,先创建被依赖的数据(并移动到 Prometheus 数据目录,使其可通过 API 访问),再回填依赖它的规则。

六、要点速查

主题 关键结论
磁盘布局 2h block(ULID 命名)+ chunks/(≤512MB 段)+ index + tombstones + meta.json;Head 靠 wal/(128MB 段)抗崩溃
压缩 目标块 = min(保留时间 × 10%, 31d);源块与新块共存会短暂超容
保留策略 默认 15d;time/size 同时设置时先触发者生效;过期清理最长滞后 2h
容量规划 retention_seconds × 摄入速率 × 1~2 字节/样本;size 上限建议 ≤ 磁盘的 80–85%
文件系统 仅支持 POSIX;NFS/EFS 明确不支持
远程集成 4 种角色(读/写 × 客户端/服务端);snappy 压缩 protobuf over HTTP;读回数据仍在本地做 PromQL 求值
回填 OpenMetrics 与 rules 两个入口;勿回填最近 3h;大 --max-block-duration 仅限非生产
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391