让我们来验证 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的压缩处理过程,感觉是这样的。