在Prometheus中,存储时间序列数据的是它自带的时间序列数据库,也被称为Prometheus存储引擎(Prometheus Storage Engine)。Prometheus存储引擎具有以下特点:
- 单机存储:Prometheus存储引擎是一种单机存储引擎,所有的时间序列数据都存储在一台服务器上。
- 持久化存储:Prometheus存储引擎将时间序列数据以持久化方式存储在本地磁盘上,这些数据在Prometheus服务器重启后仍然可用。
- 可压缩:Prometheus存储引擎可以压缩时间序列数据,以节约磁盘空间。
- 支持快照:Prometheus存储引擎支持快照(Snapshot),可以将当前的所有时间序列数据保存到一个快照文件中,以备份或迁移数据使用。
Prometheus 的存储机制
Prometheus 的存储机制基于一种称为时间序列的数据结构。时间序列是指在某个特定时间点上收集到的一组有序的数值。例如,可以用时间序列来表示 CPU 的利用率、内存的使用量、网络流量等等。
在 Prometheus 中,每个时间序列都由一个唯一的标识符(称为指标名称)和一组标签(用于区分不同的实例或服务)来标识。例如,可以使用以下指标和标签来表示一个简单的时间序列:
代码语言:javascript复制http_requests_total{method="GET", path="/api/users", status="200"}
这个时间序列表示在特定时间点上针对路径为 "/api/users" 的 HTTP GET 请求成功的总数。其中,"method"、"path" 和 "status" 都是标签,可以用来区分不同的请求。如果有多个实例同时收集此类指标,那么每个实例都会生成自己的时间序列,但指标名称和标签都是相同的。
Prometheus 的本地存储
存储配置与原理
在 Prometheus 的配置文件中,本地存储的相关配置参数主要有以下几个:
代码语言:javascript复制--storage.tsdb.path: 存储数据的目录,默认为data/,如果要挂外部存储,可以指定该目录
--storage.tsdb.retention.time: 数据过期清理时间,默认保存15天
--storage.tsdb.retention.size: 实验性质,声明数据块的最大值,不包括wal文件,如512MB
--storage.tsdb.retention: 已被废弃,改为使用storage.tsdb.retention.time
Prometheus将所有当前使用的块保留在内存中。此外,它将最新使用的块保留在内存中,最大内存可以通过storage.local.memory-chunks标志配置。
Prometheus按2小时一个block进行存储,每个block由一个目录组成,该目录里包含:一个或者多个chunk文件(保存timeseries数据)、一个metadata文件、一个index文件(通过metric name和labels查找timeseries数据在chunk文件的位置)。
最新写入的数据保存在内存block中,达到2小时后写入磁盘。为了防止程序崩溃导致数据丢失,Prometheus 的本地存储底层采用了一种称为 WAL(Write-Ahead Logging)的机制来确保数据的可靠性和一致性。WAL 机制基于日志文件,当 Prometheus 收集到新的指标数据时,它会将数据写入 WAL 文件中,然后再异步地将数据写入本地磁盘中的时间序列数据库。这种方式可以保证即使在异常情况下,如服务器崩溃或掉电等,也不会丢失任何数据。
同时Prometheus 的本地存储底层采用了一种称为 TSDB(Time Series Database)的存储格式来存储时间序列数据。TSDB 采用了一种基于时间的块存储方式,即将每个时间序列按照时间戳划分成一系列固定大小的块,并对每个块进行压缩存储。这种方式可以大幅减小存储空间,并提高查询效率。
内存缓存(In-Memory Cache)
Prometheus存储引擎首先将接收到的时间序列数据存储在内存中,以便快速响应查询请求。它采用了一种基于哈希表的数据结构,可以快速地查找和更新时间序列数据。
写入磁盘(Write to Disk)
内存中的时间序列数据会定期地写入磁盘,以保证数据的持久化存储。写入磁盘的数据被组织成一个分块(Chunk),每个分块包含一组时间序列数据和它们的样本值。分块的大小默认为512KB,可以通过配置文件进行修改。
压缩(Compression)
Prometheus存储引擎可以对分块进行压缩,以节约磁盘空间。它使用了一种名为Snappy的快速压缩算法,可以将数据压缩至原来的1/5左右。
切分(Compaction)
由于时间序列数据是不断增长的,如果不进行处理,数据量会越来越大,查询速度也会变慢。为了解决这个问题,Prometheus存储引擎采用了一种名为切分(Compaction)的技术。
切分是指将多个分块合并成一个更大的分块的过程。合并的分块可以是相邻的,也可以是跨越多个时间段的。切分的过程可以使用多个线程进行并发处理,以提高效率。切分的时机和方式可以通过配置文件进行调整。通常情况下,切分会在磁盘上的数据量达到一定阈值时触发,这个阈值可以通过配置文件中的参数进行设置。另外,Prometheus存储引擎还会定期进行自动切分,以避免数据量过大导致查询性能下降。
删除旧数据(Deleting Old Data)
由于Prometheus存储引擎采用了持久化存储方式,因此在长时间运行后,可能会出现数据量过大的情况。为了避免数据量过大导致查询性能下降,Prometheus存储引擎会自动删除一些旧的数据。
删除旧数据的方式是通过切分实现的。在切分过程中,Prometheus存储引擎会将超过一定时间范围的数据删除,以保证数据量不会过大。这个时间范围可以通过配置文件中的参数进行设置。
查询(Querying)
当用户发起一个查询请求时,Prometheus存储引擎会根据请求的时间范围和查询条件,从磁盘中读取相应的分块,并在内存中对数据进行解压缩和解码,最终返回查询结果。由于查询请求通常会涉及多个分块,因此在查询过程中,Prometheus存储引擎会自动进行分块的合并和聚合操作,以得到最终的查询结果。
Prometheus存储引擎的存储机制包括内存缓存、持久化存储、压缩、切分、删除旧数据和查询等过程。这些过程的设计和实现都旨在保证数据的可靠性、查询性能和存储效率。
Prometheus存储数据的目录结构
代码语言:javascript复制data/
|- alerts/
|- chunks/
|- head/
|- index/
|- rules/
|- snapshots/
|- wal/
下面是对每个目录的详细说明:
代码语言:javascript复制alerts/: 存储警报规则的状态信息
chunks/: 存储时序数据的块文件,每个块文件存储一段时间内的时序数据。块文件名由一组标签(label)组成,用于标识这段时间内的时序数据,例如:01D3EVB6S8SJP91GZM0RZP4YJF。
head/: 存储最近的时序数据,用于快速查询。与块文件不同,head目录存储的是最近的时序数据,而不是按时间切分的块文件。
index/: 存储指向块文件的索引信息,以便能够快速查找特定标签(label)的时序数据。
rules/: 存储告警规则的定义信息
snapshots/: 存储快照数据,用于在Prometheus重启时快速恢复数据。
wal/: 存储写入预写日志(write-ahead log)的数据。
说明
代码语言:javascript复制01D3EVB6S8SJP91GZM0RZP4YJF
├── chunks
│ └── 000001 #数据目录,每个大小为 512MB 超过会被切分为多个
├── index #索引文件,记录存储的数据的索引信息,通过文件内的几个表来查找时序数据
├── meta.json #block 元数据信息,包含了样本数、采集数据数据的起始时间、压缩历史
└── tombstones #逻辑数据,主要记载删除记录和标记要删除的内容,删除标记,可在查询块时排除样本。
远程存储
Prometheus默认支持本地存储,这样有容量的限制,Prometheus无法持久化数据,无法存储大量历史数据,同时也无法灵活扩展。为了保证Prometheus的简单性,Prometheus并没有从自身集群的维度来解决这些问题,而是定义了两种接口:remote_write/remote_read,将数据抛出去,让远程存储引擎来处理。
prometheus通过下面三种方式来实现与其他的远端存储系统对接:
- Prometheus 按照标准的格式将metrics写到远端存储
- Prometheus 可以从其他 Prometheus 服务器接收标准化格式的样本。
- Prometheus 可以从远程 URL 以标准化格式读取(返回)示例数据。
在 Prometheus 的配置文件中,远程存储的相关配置参数主要有以下几个:
代码语言:javascript复制–storage.tsdb.path:这决定了Prometheus写入数据库的位置。默认为data/。
–storage.tsdb.retention.time:这决定了何时删除旧数据。默认为15d。如果此标志设置为默认值以外的任何值,则覆盖storage.tsdb.retention。
–storage.tsdb.retention.size:[EXPERIMENTAL]这确定了存储块可以使用的最大字节数(请注意,这不包括WAL大小,这可能很大)。最早的数据将被删除。默认为0或禁用。此标志是实验性的,可以在将来的版本中进行更改。支持的单位:KB,MB,GB,PB。例如:“512MB”
–storage.tsdb.retention:不推荐使用此标志,而使用storage.tsdb.retention.time。
–storage.tsdb.wal-compression:此标志启用预写日志(WAL)的压缩。根据您的数据,您可以预期WAL大小将减少一半,而额外的CPU负载却很少。请注意,如果启用此标志,然后将Prometheus降级到2.11.0以下的版本,则您将需要删除WAL,因为它将不可读。
远程读
在远程读的流程当中,当用户发起查询请求后,Promthues将向remote_read中配置的URL发起查询请求(matchers,ranges),Adaptor根据请求条件从第三方存储服务中获取响应的数据。同时将数据转换为Promthues的原始样本数据返回给Prometheus Server。
当获取到样本数据后,Promthues在本地使用PromQL对样本数据进行二次处理。
远程写
用户可以在Promtheus配置文件中指定Remote Write(远程写)的URL地址,一旦设置了该配置项,Prometheus将样本数据通过HTTP的形式发送给适配器(Adaptor)。而用户则可以在适配器中对接外部任意的服务。外部服务可以是真正的存储系统,公有云的存储服务,也可以是消息队列等任意形式。
配置
需要将对应的地址配置下
代码语言:javascript复制remote_write:
- url: "http://localhost:9201/write"
remote_read:
- url: "http://localhost:9201/read"
远程存储的底层原理与本地存储有所不同。当 Prometheus 收集到新的指标数据时,它会将数据发送到远程存储系统中。远程存储系统可以是任何支持 Prometheus 远程写入协议的存储系统,例如 AWS S3、VictoriaMetrics等。
可以查看原文:
https://mp.weixin.qq.com/s?__biz=MzA5NTgwNzY1NA==&mid=2247484051&idx=2&sn=e570bdfd6c1163762859e74445481a03&chksm=90b8f35aa7cf7a4cd5ddc20f5ed67d43d94377c79b57a6befb987f670016d241608ab59f024d&token=1735328410&lang=zh_CN#rd
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!