开发者学堂课程【3天吃透 Prometheus:Prometheus 存储和集群】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1244/detail/18451
Prometheus 存储和集群
内容介绍:
一、如何做 Inhibit Rule
二、Prometheus 数据存储
三、Prometheus 集群
一、如何做 Inhibit Rule
此功能为前面提到过得抑制机制,在这里主要指所谓的监控项存在依赖关系时,只需要对被依赖的宕机报警而依赖项不需要告警。
例1:
假设有两个节点,节点之上运行有两个应用。一个为 DB ,一个为 MQ,显然节点还有一个 note_export 被监控。假如 Prometheus 在告警的时候发现 note_export 的监控出现了节点宕机的问题,此时 DB 和 MQ 也必然会发生宕机。因此正常情况下在告警的时候会报三个实例。即如果没有做抑制, note_export 、DB、MQ 都会告警,而在note_export 上会抓很多指标,有些指标很有可能和运行状态有关系也会告警。假设 note_export 发生宕机了,DB 和 MQ 也会顺便告警,因而为了避免像这样连续告警,我们认为如果这个节点宕机了,那么这个节点的所有应用也顺便宕机了,note_export 为被依赖项,DB 和 MQ 为依赖项,一旦 note_export 告警了,那么 DB 和 MQ 就不会再告警了,像这种我们即称为抑制机制即 Inhibit Rule 机制。
例2:
Prometheus 通过一个交换机监控了很多主机,当交换机宕机后,被监控的主机也一定抓取不到指标,长期抓取不到指标他们的状态都为0表示都宕机了,所以但交换机告警完再将主机都报一遍很没必要,还会将有用信息全淹没,此时交换机为被依赖项,三个主机为依赖项,而且每个主机上还会有附录可能也会要告警就容易被淹没。为了避免这种场景,我们应该对这种场景定义 Inhibit Rule。定义 Inhibit Rule时要根据每个人的环境都不一样,依赖关系也不一样从而根据实际情况去定义。
1、如何定义 Inhibit Rule
Inhibit Rule 语法格式在 Prometheus 的 Alerting rules 目录上格式如下:
source_match: [ : ,…]source_match_re [: ,…][equal: ‘[‘,…’]’] target_match://支持字符串精确匹配 [:,…]target_match_re: //正则表达式模式匹配 [: ,…]
source_match 意思是如果已经已经发送一个告警信息,而那个告警的标签能匹配到当前规则中的 target_match 所定义的匹配条件,或者 target_match_re 匹配条件的时候,如果有新的告警可以满足source_match 或者 source_match_re 的话,那这个告警信息就被认为与我们的目标标签完全相同,就会启动抑制机制新的告警就不会被发送。
例子:
source_match: alertname[ NodeDown //告警规则名字 severity:criticaltarget_match: //另外一个新的告警 severity:critical
equal: //如果前后两个告警的 node 标签的值相同的话,就认为是同一个节点上的。note 也会告警,为了避免服务告警就需要用抑制规则。如果目标告警 target_match 也是 critical 级别,并且告警上 node 标签的值与原来曾经发送过的告警的标签的值一样,就认为是同一个节点如果集群中的某一个节点或者说主机因为主机宕机使得NodeDown 被告警了,同时告警规则中还定义了安全级别 critical。因为主机宕机所以主机上的服务也都会宕机,主机告警服务的服务,所以就不再告警。
例:
up{node=”node01.magedu.com”,instance=”node01.magedu.com:9100”,,,,}==0severity:critical //宕机后附加的值ALERT{node=”node01.magedu.com”,instance=”node01.magedu.com:9100“,severity=critical}
//因为节点宕机了,所以会发送一次告警,而告警上的标签是复制上面的标签并且会加上一个新的标签.节点宕机导致节点是的歌来发也宕机了。歌来发宕机 导致下面的 severity 抓的up值也宕机也产生新告警。
up{node=”node01.magedu.com”,instance=”node01.magedu.com:3000”,,,,} severity:critical ALERT{node=”node01.magedu.com”,instance=”node01.magedu.com:3000“,severity=critical}
//以此前发送过一次的告警为源发送新的告警,新的告警发送前第一要判断严重级别是否是 critical,第二要确定 note 的标签值与前面发送的标签值是否相同,如果一样则认为是同一个节点告警,第二个告警就有可能是因为第一个节点宕机导致的,则不需要再次告警。
当使用交换机来监控时逻辑相同,在交换机上打一个标签分辨不同交换机,所有主机打上标签说明连接的是哪个交换机,当交换机宕机时,显然后面的所有主机都不需要告警。对每个主机而言,如果主机宕机了,主机上的服务也宕机时,但因为用的节点名字一致也不会再报警,则可能需要加很多条抑制规则。
2、静默机制
有些时候服务处于例行维护状态时,手动将节点宕机因此没必要告警就叫静默机制,在告警的 Slience 处可以自己定义,临时静默时间一到就会失效。
界面如下:New Slience 指明静默时间区间,这种为临时静默超过规定时间后即会失效,也可以定义周期性静默只是较为麻烦,若维护不是例行的使用临时静默即可。
在 Alertmanger 里面的工具 amtool 也能接入到alertmanger去帮助管理静默,查询规则。它可以添加静默、防止静默过期、查询静默定义、更新静默。 amtool 是alertmanger的命令行客户端管理工具,一些高级的静默条件可以在 amtool Slience处定义。
二、Prometheus 数据存储
1、Prometheus 本地存储概述
(1)Prometheus 内置了 TSDB 该存储经历了三个版本;
(TSDB 是Prometheus 的抓取器,它抓取的每一个指标都会有 TSDB 存储引擎存储下来,最终 TSDB 存储到文件系统上表现为文件。但在解析的时候会按照 TSDB 的存储引擎进行解析。)
v1.0:LeveIDB,性能不高,每秒只能接收50000个样本;(在Prometheus0.1,1.0时代用的都是v1.0时代, LeveIDB 是独立项,可认为是 TSDB 数据库。)
v2.0: LeveIDB,但使用了 Facebook 的 Gorilla 压缩算法,极大地压缩了单个样本的大小,每秒可接收的样本提升到80000个;
V3.0:由 Prometheus2.0 时引入,是一个独立维护的 TSDB 开源项目;在单机上,每秒可处理数百万个样本;(此时已不再用 LeveIDB 作为数据库,使用的是重新研发的 TSDB,如今用的是V3.0存储引擎)
(2)Prometheus TSDB数据存储格式概览
以每2小时为一个时间窗口,并存储为一个单独的 block;
block 会压缩、合并历史数据块,随着压缩合并,其 block 数量会减少;
block 的大小并不固定(因为抓取的时间间隔,样本大小不一样),但最小会保存两个小时的数据;
新数据的保存:如上图中,Head 是保存在内存中的,即当前块是在内存中保存,所有的指标样本数据都被 Prometheus 直接在内存中保存,显然在比较大的环境中 Prometheus 是比较吃内存的。为了确保样本数据能够持久,防止 Prometheus 宕机数据就丢失,所以Head 会对每一个接收到的样本过一段时间后会试图持久到磁盘上用基于内存映射的方式映射到磁盘上,这样即使宕机了磁盘里的数据还在,再用的时候把内容再用于内存就可以,这些数据每一个样本会被以WAL (类似于 AOF ,仅追加的写日志,不会更改里面的数据为顺序写速度很快)的方式存储下来。Head 里面为了避免过于占用内存,所以每过段时间以追加写的方式保存在 WAL 当中,而后每当一个时间窗口到达以后就把里面的数据合并存放到新生成一个的 block 中。数据被源源不断的运进去,源源不断的存储成 block。
每个 block 都有单独的目录,因为每个 block 自己里面要保持的不光是样本数据,要想查询的话需要在样本数据上做检索为了能查询需要在上面做索引。查询时根据索引查。
2、TSDB Block
每个block都有自己的目录,里面包含该时间窗口内所有的hmkindex、tombstones、meta.json 每个 block 都有单独的目录,因为每个 block 里面要保持的不光是样本数据,要想查询的话需要在样本数据上做检索为了能查询需要在上面做索引。查询时根据索引查。
chunk 可以认为是固定大小的数据块,每个 Block 默认有128MB,由大量128MB数据块加起来组织成一个 Block,一个 Block 用一个目录来代表不是一个单独的文件。
chunks:用于保存时序数据,每个 chunk 的大小为512MB,超出该大小时则截断并创建为另一个 Chunk;各 Chunk 以数字编码;
index:索引文件,它是 PrometheusTSDB实现高效查询的基础;我们甚至可以通过 Metrics Namc和Labcls 查询时间序列数据在chunk 文件中的位置;索引文件会将指标名称和标签索引到样本数据的时间序列中;
tombstones(墓碑):用于对数据进行软删除,即“标记删除”,以降低删除操作的成本;删除的记录并保存在 tombstoncs 文件中,而在读取时间序列上的数据时,会基于 tombstones 进行过滤已经删除的部分;(被删除的部分在下一次做块合并的时候才会真正执行删除操作。因为块本身只是目录所以它还可以合并,过段时间才会在后台执行随机写操作。将该删除的删除,该压缩的压缩,该合并的合并,进而更好的节约磁盘空间。
metajson: block 的原始数据信息,这些原始数据信息是 block 的合并、删除等操作的基础依赖。(可以想象成每个 block 是独立的文件系统,里面保存有自己的文件,文件文件之间有连接关系,文件内部的数据还有索引,可以把一个 block 想象成一个数据库。)
正常情况下如果使用二进制直接启动, Prometheus 会在当前目录下创建一个 data 目录用来保存数据,对 block 目录而言 chanks 里面放的是各个 chank,各个 chank 是有编号的,除此外还包含index索引、meta.json、tombstones。而当前正在操作的数据在数据目录下的chunks_head中,它会不断刷到wal中,不断填入到chunks_head 中,当 chunks_head 填满足够两个小时后就会生成一个新的 block。
3、WAL(Write-Ahead Logging)
预写日志,预写意味着把所有的随机写先做成顺序写然后再合并到block中,因此性能非常好。
在前面的图中, Head 块是数据库位于内存中的部分, Block(灰色块)是磁盘上不可更改的持久块,而预写日志(WAL)用于辅助完成持久写入;
输入的样本(t,v)首先会进入 Head,并在内存中停留一会儿,然后马上被刷写到磁盘并映射进入内存中(M-map);
当这些内存映射的块或内存中的块老化到一定程度时,它将作为持久块刷写到磁盘;
随着它们的老化进程,将合并更多的块,最终在超过保留期限后被删除;
WAL是在数据库中发生的事件的顺序日志,在写入/修改/删除数据库中的数据之前,首先将事件记录(附加)到 WAL中,然后在数据库中执行必要的操作;
WAL的关键点在于,用于帮助 TSDB 先写日志,再写磁盘上的 Block;
WAL被分割为默认128MB大小的文件段,它们都位于WAL目录下;
使用WAL技术可以方便地进行圆润、重试等操作;
WAL日志的数量及截断的位置则保存在 chcckpoint 文件中,该文件的内容要同步写入磁盘,可以确保其可靠性;(chcckpoint被认为是wal 多个文件的索引偏移值的定义,显然如果这个文件崩了,WAL可能就合并不起来)