存储
Prometheus 包含一个本地磁盘时序数据库,但也可以选择与远程存储系统集成。
本地存储
Prometheus 的本地时序数据库以一种自定义且极其高效的格式将数据存储在本地存储中。
磁盘布局
摄入的样本按两小时分为一个块(Block)。每个块由一个目录组成,该目录包含一个 chunks 子目录(包含该时间窗口内的所有时序样本)、一个元数据文件(metadata)和一个索引文件(index,用于将指标名称和标签映射到 chunks 目录中的时序)。chunks 目录中的样本被组织成一个或多个段(segment)文件,默认情况下每个文件最大为 512 MB。当通过 API 删除序列(series)时,删除记录将存储在独立的 tombstone 文件中,而不是立即从 chunk 段中移除。
当前接收样本的块保存在内存中,并未完全持久化。为了防止崩溃,它通过预写日志(WAL)进行保护,该日志可以在 Prometheus 服务器重启时重新播放。预写日志文件存储在 wal 目录中,每个段为 128MB。这些文件包含尚未经过压缩合并的原始数据,因此它们通常比普通块文件大得多。Prometheus 将至少保留三个预写日志文件。高流量的服务器可能会保留三个以上的 WAL 文件,以便保存至少两个小时的原始数据。
Prometheus 服务器的数据目录看起来像下面这样
./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
请注意,本地存储的一个限制是它没有集群化或副本。因此,在面临磁盘或节点故障时,它不能任意扩容,也无法保证高可用性,应该像对待其他单节点数据库一样进行管理。通过合理的架构设计,完全可以在本地存储中保留数年的数据。
推荐使用快照(Snapshots)进行备份。在不使用快照的情况下进行备份可能会面临丢失自上一个 TSDB 块创建以来所记录的数据的风险,这通常每两小时发生一次,覆盖最近三小时的样本。在备份或恢复时排除 WAL 文件(storage.tsdb.path 中的 chunks_head/、wal/ 和 wbl/ 目录)无论如何都能确保备份的一致性,代价是丢失 WAL 文件覆盖的时间范围。
或者,可以通过远程读/写 API 使用外部存储。由于这些系统在可靠性、性能和效率方面差异巨大,因此需要对它们进行仔细评估。
有关文件格式的更多详细信息,请参阅 TSDB 格式 。
压缩合并
最初的两小时块最终会在后台被压缩合并为更长的块。
压缩合并将创建更大的块,其中包含跨度达保留时间 10% 或 31 天的数据(以较小者为准)。
运维方面
Prometheus 有几个配置本地存储的启动参数(Flag)。最重要的包括
--storage.tsdb.path: Prometheus 写入其数据库的路径。默认为data/。--storage.tsdb.retention.time: 样本在存储中保留的时间。如果既没有设置此参数,也没有设置storage.tsdb.retention.size,则保留时间默认为15d。支持的单位有:y, w, d, h, m, s, ms。--storage.tsdb.retention.size: 要保留的存储块的最大字节数。最旧的数据将被首先删除。默认为0或禁用。支持的单位有:B, KB, MB, GB, TB, PB, EB。例如:"512MB"。基于 2 的幂,因此 1KB 为 1024B。为了满足此保留策略,只有持久化的块会被删除,尽管 WAL 和内存映射(m-mapped)的 chunk 也会计算在总大小中。因此,对磁盘的最低要求是wal(WAL 和 Checkpoint)和chunks_head(内存映射的 Head chunk)目录所占用的峰值空间之和(每 2 小时达到一次峰值)。--storage.tsdb.wal-compression: 启用预写日志(WAL)的压缩。根据您的数据,可以预期 WAL 大小会减半,而 CPU 额外负载极低。此参数在 2.11.0 版本中引入,并在 2.20.0 版本中默认启用。请注意,一旦启用,如果将 Prometheus 降级到 2.11.0 以下的版本,将需要删除 WAL。
Prometheus 平均每个样本仅存储 1-2 个字节。因此,要规划 Prometheus 服务器的容量,可以使用以下粗略公式
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample
要降低样本摄入速率,您可以减少抓取的时序数量(减少目标或减少每个目标的时序数量),或者增加抓取间隔。然而,由于同一时序内样本的压缩效果,减少时序数量通常会更加有效。
如果您的本地存储损坏到 Prometheus 无法启动的程度,建议备份存储目录并从备份中恢复受损的块目录。如果您没有备份,最后的手段是删除损坏的文件。例如,您可以尝试删除单个块目录或预写日志(WAL)文件。请注意,这意味着会丢失这些块或 WAL 所覆盖的时间范围内的数据。
注意Prometheus 的本地存储不支持非 POSIX 兼容的文件系统,因为可能会发生无法恢复的损坏。不支持 NFS 文件系统(包括 AWS 的 EFS)。NFS 本可以是 POSIX 兼容的,但大多数实现并非如此。为了保证可靠性,强烈建议使用本地文件系统。
如果同时指定了时间和大小保留策略,则以先触发的为准。
过期块的清理在后台进行。删除过期块可能需要长达两个小时。块必须完全过期后才会被移除。
合理规划保留大小
如果您正在使用 storage.tsdb.retention.size 来设置大小限制,您需要考虑该值相对于您为 Prometheus 分配的存储空间的合理大小。降低保留大小以提供缓冲区是明智的,这样可以确保在为 Prometheus 分配的存储空间填满之前删除较旧的条目。
目前,我们建议将保留大小最多设置为分配给 Prometheus 磁盘空间的 80-85%。这增加了在达到任何磁盘限制之前删除较旧条目的可能性。
远程存储集成
Prometheus 的本地存储受限于单节点的扩展性和可靠性。Prometheus 并没有试图在自身内部解决集群化存储的问题,而是提供了一套接口,允许与远程存储系统集成。
概述
Prometheus 通过以下四种方式与远程存储系统集成
- Prometheus 可以将摄入的样本以 远程写入(Remote Write)格式 写入到远程 URL。
- Prometheus 可以从其他客户端以 远程写入(Remote Write)格式 接收样本。
- Prometheus 可以从远程 URL 以 远程读取(Remote Read)格式 读取(回读)样本数据。
- Prometheus 可以将客户端请求的样本数据以 远程读取(Remote Read)格式 返回。

远程读写协议都在 HTTP 上使用经 snappy 压缩的 Protocol Buffer 编码。读取协议目前尚未被视为稳定的 API。
写入协议包含 1.0 版本的稳定规范 和 2.0 版本的实验性规范,Prometheus 服务器均支持这两者。
有关在 Prometheus 中作为客户端配置远程存储集成的详细信息,请参阅 Prometheus 配置文档中的 远程写入(remote write) 和 远程读取(remote read) 部分。
请注意,在读取路径上,Prometheus 仅从远程端获取一组标签选择器和时间范围的原始时序数据。对原始数据的所有 PromQL 评估仍发生在 Prometheus 自身中。这意味着远程读取查询存在一定的扩展性限制,因为所有必要的数据必须首先加载到进行查询的 Prometheus 服务器中,然后在那里进行处理。然而,目前对 PromQL 的完全分布式评估支持被认为是不可行的。
Prometheus 也提供这两个协议的服务。内置的远程写入接收器可以通过设置 --web.enable-remote-write-receiver 命令行参数来启用。启用后,远程写入接收器端点为 /api/v1/write。远程读取端点可在 /api/v1/read 上访问。
现有集成
要了解有关与远程存储系统现有集成的更多信息,请参阅 集成文档。
从 OpenMetrics 格式回填数据
概述
如果用户想要将 OpenMetrics 格式的数据导入 TSDB 中创建数据块,可以通过数据回填(backfilling)来实现。然而,他们应该小心并注意,回填最近 3 小时内的数据(当前的 head 块)是不安全的,因为这个时间范围可能会与 Prometheus 仍在修改的当前 head 块重叠。回填将创建新的 TSDB 块,每个块包含两小时的指标数据。这限制了创建块时的内存需求。两小时块压缩为更大块的工作随后由 Prometheus 服务器自身完成。
一个典型的用例是将指标数据从其他监控系统或时序数据库迁移到 Prometheus。为此,用户必须首先将源数据转换为 OpenMetrics 格式,这是下文所述回填过程的输入格式。
请注意,由于无法在 OpenMetrics 格式中表示,此过程不支持原生直方图和陈旧性标记。
用法
数据回填可以通过 promtool 命令行进行。promtool 将把数据块写入一个目录中。默认情况下,此输出目录为 ./data/,您可以通过在子命令中使用所需输出目录的名称作为可选参数来更改它。
promtool tsdb create-blocks-from openmetrics <input file> [<output directory>]
创建块后,将其移动到 Prometheus 的数据目录中。如果与 Prometheus 中现有的块存在重叠,则对于 v2.38 及以下版本的 Prometheus,需要设置 --storage.tsdb.allow-overlapping-blocks 参数。请注意,任何回填的数据都受您为 Prometheus 服务器配置的保留策略(按时间或大小)的约束。
更长的块持续时间
默认情况下,promtool 将对块使用默认的块持续时间(2h);这种行为是最通用且正确的。然而,当在很长的时间范围内回填数据时,使用更大的块持续时间值可能会更有利,以便更快地进行回填,并防止 TSDB 随后进行额外的压缩合并。
--max-block-duration 参数允许用户配置块的最大持续时间。回填工具将选择一个不大于此值的合适块持续时间。
虽然较大的块可以提高回填大型数据集的性能,但也存在缺点。在基于时间的保留策略下,即使(可能很大的)块中只有单个样本仍在保留策略范围内,也必须保留整个块。相反,在基于大小的保留策略下,即使 TSDB 仅稍微超出大小限制,也会删除整个块。
因此,通过选择较大的块持续时间来减少回填生成的块数量必须谨慎进行,不建议在任何生产实例中使用。
记录规则的数据回填
概述
当创建新的记录规则时,该规则没有历史数据。记录规则数据仅从创建时间开始存在。promtool 使得创建历史记录规则数据成为可能。
用法
要查看所有选项,请使用:$ promtool tsdb create-blocks-from rules --help。
使用示例
$ promtool tsdb create-blocks-from rules \
--start 1617079873 \
--end 1617097873 \
--url http://mypromserver.com:9090 \
rules.yaml rules2.yaml
提供的记录规则文件应该是一个正常的 Prometheus 规则文件。
promtool tsdb create-blocks-from rules 命令的输出是一个目录,其中包含记录规则文件中所有规则的历史规则数据块。默认情况下,输出目录为 data/。为了使用这些新的块数据,必须将这些块移动到运行中的 Prometheus 实例数据目录 storage.tsdb.path 中(对于 v2.38 及以下版本的 Prometheus,必须启用 --storage.tsdb.allow-overlapping-blocks 参数)。移动后,在下一次运行压缩合并时,新的块将与现有的块合并。
局限性
- 如果您多次运行规则回填且开始/结束时间存在重叠,则每次运行规则回填时都会创建包含相同数据的块。
- 记录规则文件中的所有规则都将被评估。
- 如果在记录规则文件中设置了
interval(时间间隔),它将优先于规则回填命令中的eval-interval参数。 - 目前,如果记录规则文件中包含告警,它们会被忽略。
- 同一组中的规则无法看到之前规则的结果。这意味着不支持引用其他正在回填的规则的规则。一种解决方法是多次进行回填,首先创建依赖的数据(并将依赖的数据移动到 Prometheus 服务器的数据目录中,以便可以通过 Prometheus API 访问它)。