让我们来验证 Prometheus 2.0 中存储 Compaction 的运行情况
普罗米修斯圣诞节日历2017年第三天
这是一篇文章。
本文总结了关于Prometheus 2.0存储方面的官方文档内容和功能的验证结果。
环境
-
- prometheus server 2.00
- centos7.4
这篇文章将以 Prometheus 2.0 为主题。
最近发布了2系列,但2系列的数据格式与1系列完全不同。而且,这是一个不兼容的变化,因此1.8版本的Prometheus无法处理由2.0生成的数据。这是一个重大变更。
在搜索Prometheus存储的文章时,会出现一些结果,但目前大多是针对1.x版本的Prometheus。我认为在网络上搜索的信息应该确认是哪个版本的文章。另外,官方文件中的解释过于简洁。与1.8版本的文件相比,信息的量差别明显。
有关1.8和2.0数据的互通性
在先前的句子中已经提到,2.x版本的数据格式与1.x版本完全不同。并且它们之间是不兼容的。然而,在一些已经收集了1.8版本数据且无法轻易迁移的情况下,可以通过同时运行1.8和2.0版本的Prometheus,并在2.0版本的Prometheus中使用远程读取设置,从1.8版本的Prometheus中拉取数据来解决这个问题。
具体而言,可以在1.8版的Prometheus启动时使用以下标志:
$ ./prometheus-1.8.1.linux-amd64/prometheus -web.listen-address ":9094" -config.file old.yml
接下来,启动2.0版本的Prometheus,不需要特殊的标志,只需要指定config.file即可。
$ ./prometheus-2.0.0.linux-amd64/prometheus --config.file prometheus.yml
在 Prometheus 2.0 的配置文件中,添加 remote_read 设置。作为远程读取的目标,指定正在同一台机器上运行的 Prometheus 1.8 监听的端口和 API。
remote_read:
- url: "http://localhost:9094/api/v1/read"
# 存储布局
普罗米修斯2.0采用了名为Macro Design的存储结构。
宏观设计是什么意思?
Prometheus存储的所有数据都是通过树形目录布局进行管理的。
可以用以下的形象来表达。
$ tree ./data
./data
├── lock (text file)
├── block (directory)
│ ├── chunks (directory)
│ │ ├── 000001(chunk binary file)
│ │ ├── 000002
│ │ └── 000003
│ ├── index (binary file)
│ └── meta.json
├── block
│ ├── chunks
│ │ ├── 000001
│ │ ├── 000002
│ │ └── 000003
│ ├── index
│ └── meta.json
└── wal (directory)
├── 000001 (wal binary file)
└── 000002
用词
关于存储的术语和意义
-
- data point:
-
- timestampとvalueのタプル
-
- series:
-
- data pointの連続。時系列。
-
- block:
-
- ディレクトリ。頭に必ず”b”がつく。indexファイルとchunkディレクトリが格納される。
-
- chunk:
-
- ディレクトリ。chunkディレクトリ内のchunkファイルはバイナリデータ。複数のseriesのdata pointを格納する。
-
- index:
-
- バイナリデータ。chunk内のseriesにメトリック名とラベルを紐付けるファイル。
-
- meta.json:
-
- meta.json。該当ブロックの状態(圧縮階層や、chunkの数などの情報)を記録したファイル。json形式なので参照可能。
-
- tombstone:
- APIで削除された時系列データ。削除処理後に直ちに削除されるのではなく、tombstoneファイルとして保管される。
存储选项
以下是提供给Prometheus的存储选项:
1. Prometheus的存储选项有哪些?
2. 可以用来作为Prometheus存储的选项有哪些?
3. Prometheus的存储选项有哪些可供选择?
4. 以下是可以用作Prometheus存储的选项。
-
- –storage.tsdb.path
-
- データを保管するパスを指定します。デフォルトではprometheusのバイナリと同じ階層にdataというディレクトリが作成されます。systemdでサービス化しているなどの場合は、このオプションで指定しておかないと/直下にdataディレクトリが作成されてしまいます。
-
- –storage.tsdb.retention
-
- データを保管する期間を指定します。デフォルトは15日です。
-
- –storage.tsdb.min-block-duration
-
- ブロックの最小期間を指定します。デフォルトは2時間です。このオプションで設定した間隔でメモリからデータがディスクにブロックとして書き出されます。
-
- –storage.tsdb.max-block-duration
- 束ねられたブロックの最大の期間を設定します。デフォルトは36時間です。この値はデフォルトのretention期間である15日の10%になっています。
TSDB 构成要素
-
- Block 小さなデータベース
-
- mmap
-
- Compaction ブロックのコンパクト処理
-
- Retention データ保管
- Index
将下面的句子用中文进行本地化改写,只需要提供一种选项:
## Block
在宏观设计的最高层次中,位于顶层的区块被视为一个独立的数据库。每个区块包含在其时间范围内收集的分块文件集合和索引。
Prometheus收集的数据会同时记录在内存中和作为临时文件写入wal目录。当内存中记录的数据收集时间达到–storage.tsdb.min-block-duration所设定的时间后,它们将作为数据块写入到磁盘中。一旦作为数据块写入,其内容就无法更改。最新的数据始终以原始数据的形式记录在内存和wal目录中。wal目录中记录的数据可用于避免在Prometheus重新启动时丢失内存中的数据。一旦写入数据块,作为临时文件的wal内容将被清除,并写入下一个最新样本的数据块。
查询处理是以块为单位进行的。对于查询处理中指定的时间范围(一天、一周、从何时到何时等),所有符合条件的块都将被视为处理对象,并对多个块进行查询,将从每个块返回的结果合并并显示为一个结果。
数据以块为单位存储和删除。删除时只需删除块=目录,因此处理会在瞬间完成,不必再担心像Zabbix那样需要付出负载来处理清理的问题。
## mmap
内存映射
## 压缩
关于块的压缩处理。
為了不在內存中累積大量數據,我們默認以2小時為單位來生成block。按照這個規格,一天會生成12個block,如果執行一周時間的查詢操作,需要對84個block進行簡單計算並執行查詢,還需要合併每個block獲得的結果。合併操作也需要成本。
因此,我们进行block的Compaction。将多个block合并为一个block,并将其转换为覆盖更大时间范围的block。通过Compaction处理,一个block覆盖的时间范围会增加,但并非无限增长,而是受到–storage.tsdb.max-block-duration设置的限制。默认为36小时。这个36小时的值是根据默认的retention期限15天的10%进行设置的参考值。在Compaction过程中,会删除已标记为删除的数据(tombstone),并重新组织chunk以提高查询性能。
保留
在基于区块链的设计中,如何删除旧数据?
只需要通过一个非常简单的思路,删除超过设定的保留期限之外的block目录。通过之前的压缩处理,随着block的变老,它们的大小也会增加。但是因为可以设置block的最长期限,所以不会导致数据库无限增长。
指数
调音
调整的观点有以下两个方面。
-
- ターゲットを減らす
- 取得間隔を伸ばす
减少目标数量
要减少目标,
-
- 不要なホストを取得対象から除外する
-
- ジョブが取得するメトリクスを減らす
- 例えば、node_exporterであれば、param > collcter の設定で、このジョブはこのcollecterが収取するmetricだけを対象に保管する。など。
延长时间间隔
通过增加抓取间隔来实现。
在 Prometheus 的 config.file 中,可以调整 scrape_interval 的值,可以以全局单位或作业单位进行调整。
我试着确认了一下Compaction的运作。
我尝试确认了一下紧凑处理的动作。
为了更方便确认,我们将 –storage.tsdb.min-block-duration 设置为5分钟[5m]。
起动后的数据目录。已生成了锁文件和wal目录。顺便说一下,是在16:18启动的。
ls -lh /usr/local/prometheus/data/
total 4.0K
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
# ls -lh /usr/local/prometheus/data/wal/
total 256M
-rw-r--r--. 1 root root 256M Dec 1 16:22 000001
过了5分钟,生成了一个方块。
# ls -lh /usr/local/prometheus/data
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:22 01C08F92RNPS54R981GXQQANWT ←これができた
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
我将检查已完成的块目录的内容。其中包括块目录本身,块目录中的生数据,索引文件和元文件。
# ls -lh /usr/local/prometheus/data/01C08F92RNPS54R981GXQQANWT/
total 308K
drwxr-xr-x. 2 root root 20 Dec 1 16:22 chunks
-rw-r--r--. 1 root root 299K Dec 1 16:22 index
-rw-r--r--. 1 root root 277 Dec 1 16:22 meta.json
-rw-r--r--. 1 root root 9 Dec 1 16:22 tombstones
# ls -lh /usr/local/prometheus/data/01C08F92RNPS54R981GXQQANWT/chunks/
total 64K
-rw-r--r--. 1 root root 64K Dec 1 16:22 000001
我会查看meta.json的内容。
在stats中,您可以查看该块存储的样本数量、时间序列数量和块数量。此外,compaction显示了该块的压缩状态。由于这是第一块,所以level=1,sources是自己块的名称。
{
"version": 1,
"ulid": "01C08F92RNPS54R981GXQQANWT",
"minTime": 1512112500000,
"maxTime": 1512112800000,
"stats": {
"numSamples": 15364,
"numSeries": 2103,
"numChunks": 2103
},
"compaction": {
"level": 1,
"sources": [
"01C08F92RNPS54R981GXQQANWT"
]
}
}
再过五分钟。又完成了一个区块。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:22 01C08F92RNPS54R981GXQQANWT ←1個目
drwxr-xr-x. 3 root root 68 Dec 1 16:27 01C08FJ7QNBM5SX8Z3WRZ5JA7C ←2個目
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
这是第二个块的块目录的内容。
# ls -lh data/01C08FJ7QNBM5SX8Z3WRZ5JA7C/chunks/
total 88K
-rw-r--r--. 1 root root 85K Dec 1 16:27 000001
第一个块的meta.json几乎与其相同。
# cat data/01C08FJ7QNBM5SX8Z3WRZ5JA7C/meta.json
{
"version": 1,
"ulid": "01C08FJ7QNBM5SX8Z3WRZ5JA7C",
"minTime": 1512112800000,
"maxTime": 1512113100000,
"stats": {
"numSamples": 41991,
"numSeries": 2101,
"numChunks": 2101
},
"compaction": {
"level": 1,
"sources": [
"01C08FJ7QNBM5SX8Z3WRZ5JA7C"
]
}
}
再过5分钟。原本存在的2个方块消失了,另一个方块被组装完成。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
我们将检查新创建的模块的 meta.json 文件。
{
"version": 1,
"ulid": "01C08FVCRVVPTPSP6ESA7WF0GH",
"minTime": 1512112500000,
"maxTime": 1512113400000,
"stats": {
"numSamples": 99375,
"numSeries": 2108,
"numChunks": 6305
},
"compaction": {
"level": 2,
"sources": [
"01C08F92RNPS54R981GXQQANWT", ←1個目のブロック
"01C08FJ7QNBM5SX8Z3WRZ5JA7C", ←2個目のブロック
"01C08FVCPN1FA903ZVZPE7Y6EW" ←3個目のブロック
]
}
compaction的级别变为2,并且显示了3个block名称在sources中。
在sources中显示的3个模块中,前两个是之前就存在的模块。也就是说,这些模块已经存在并与生成第3个模块的时机一起被捆绑为一个新的模块。
通过查看统计数据,可以看出numChunks大致等于一个块的值乘以3,因此可以简单地将它们看作是三个块的组合。
这个级别从1升至2表明这个块经历了一次compaction处理。
再过5分钟,新的区块被创建出来了。
# ll data/
total 4
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←これがレベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:37 01C08G4HNN7SH8C08N39AE9QH0 ←これがレベル1
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
到这个阶段,预计在接下来的5分钟内会完成一个新的level=1的块,再过5分钟后,由刚刚完成的块进行compaction形成level=2的块。关于compaction处理,例如level=1的块需要聚集多少个才能升级为level=2,还未调查,将来也希望确认这一点。
5分钟后的状态。加入了一个等级为1的方块。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←レベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:37 01C08G4HNN7SH8C08N39AE9QH0 ←レベル1
drwxr-xr-x. 3 root root 68 Dec 1 16:42 01C08GDPMNVAH1AFVNCWXAM97S ←レベル1
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
再过5分钟。正如预期的那样,一个新的level=2的区块已经完成了。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←前からあるレベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:47 01C08GPVNR8WSV2VZYMS5C2EJJ ←あたらしくできたレベル2
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
我将检查新创建的level=2的块的meta.json文件。我确认它的行为与上次的压实操作相同。
# cat data/01C08GPVNR8WSV2VZYMS5C2EJJ/meta.json
{
"version": 1,
"ulid": "01C08GPVNR8WSV2VZYMS5C2EJJ",
"minTime": 1512113400000,
"maxTime": 1512114300000,
"stats": {
"numSamples": 126060,
"numSeries": 2101,
"numChunks": 6303
},
"compaction": {
"level": 2,
"sources": [
"01C08G4HNN7SH8C08N39AE9QH0", ←すでにあったレベル1
"01C08GDPMNVAH1AFVNCWXAM97S", ←すでにあったレベル1
"01C08GPVKN0VNVQVK4752277WA"
]
}
}
我们可以进一步进行。增加了两个level=1的模块。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←レベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:47 01C08GPVNR8WSV2VZYMS5C2EJJ ←レベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:52 01C08H00JNJTDWZ9QDYV0Q57GC ←レベル1
drwxr-xr-x. 3 root root 68 Dec 1 16:57 01C08H95HNNKYC5EZ0R6ND7Q6S ←レベル1
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
在下一次生成过程中,产生了三个级别为2的。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←レベル2
drwxr-xr-x. 3 root root 68 Dec 1 16:47 01C08GPVNR8WSV2VZYMS5C2EJJ←レベル2
drwxr-xr-x. 3 root root 68 Dec 1 17:02 01C08HJAJS6D3A93MZ24YDM2EE←レベル2
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
刚刚创建的level=2的meta.json
# cat data/01C08HJAJS6D3A93MZ24YDM2EE/meta.json
{
"version": 1,
"ulid": "01C08HJAJS6D3A93MZ24YDM2EE",
"minTime": 1512114300000,
"maxTime": 1512115200000,
"stats": {
"numSamples": 126076,
"numSeries": 2102,
"numChunks": 6304
},
"compaction": {
"level": 2,
"sources": [
"01C08H00JNJTDWZ9QDYV0Q57GC",
"01C08H95HNNKYC5EZ0R6ND7Q6S",
"01C08HJAGNWG11TJ9CWC465PSR"
]
}
}
在放置等级=2时,直到又创建了一个等级=2才生成了等级=3的方块。
# ls -lh data/
total 4.0K
drwxr-xr-x. 3 root root 68 Dec 1 16:32 01C08FVCRVVPTPSP6ESA7WF0GH ←level=2
drwxr-xr-x. 3 root root 68 Dec 1 17:17 01C08JDSJGK6WFRCQFYDE4QZED ←level=3
-rw-------. 1 root root 5 Dec 1 16:18 lock
drwxr-xr-x. 2 root root 20 Dec 1 16:18 wal
我将查看Level 3的block的meta.json。在sources中显示了9个block,它们都是Level 1的block。
# cat data/01C08JDSJGK6WFRCQFYDE4QZED/meta.json
{
"version": 1,
"ulid": "01C08JDSJGK6WFRCQFYDE4QZED",
"minTime": 1512113400000,
"maxTime": 1512116100000,
"stats": {
"numSamples": 378273,
"numSeries": 2103,
"numChunks": 18914
},
"compaction": {
"level": 3,
"sources": [
"01C08G4HNN7SH8C08N39AE9QH0",
"01C08GDPMNVAH1AFVNCWXAM97S",
"01C08GPVKN0VNVQVK4752277WA",
"01C08H00JNJTDWZ9QDYV0Q57GC",
"01C08H95HNNKYC5EZ0R6ND7Q6S",
"01C08HJAGNWG11TJ9CWC465PSR",
"01C08HVFFNM8E37KZHCS6R50YC",
"01C08J4MENJ4DR6KDR6BB4CTMK",
"01C08JDSDN6GSRDXW0Q1364S0R"
]
}
}
我实际验证了Prometheus的压缩处理过程,感觉是这样的。