凯发平台-凯发旗舰厅 > 四川小吃 > prometheus监控没有的指标(prometheus监控数据指标)
2023
10-02

prometheus监控没有的指标(prometheus监控数据指标)-凯发平台

缺少协议参数data是什么意思 prometheus 指标数据缺失nodata的告警处理

无论哪种监控系统,都会基于采集的数据进行告警规则的配置。无论是传统监控系统的代表zabbix,还是云原生时代的监控利器prometheus,以及其他监控系统,数据缺失问题(即nodata)是都需要面对的问题

01 问题

首先解释一下本文提到的指标缺失场景,在使用过程中有两种情况:

一种是在配置告警规则的时候,该指标数据就不是全量数据;例如配置宕机告警时,使用up==0作为告警规则,某一台主机由于各种原因,指标 up 的数据一直不存在。 这种带来的问题就是缺失的指标永远不会告警。一种则是在告警规配置的时候,指标数据是完整的,当在告警生效一段时间以后,且发出异常告警之后,出现指标数据缺失的问题。例如配置 mem_used_percent > 90(内存使用率超过90%告警),某台设备已经超限并且触发了告警规则,此时服务器由于网络原因,没能上报数据,导致数据缺失。 这种带来的问题就是可能出现假恢复的情况。

02 解决方法

zabbix系统中一般采用nodata触发器,当监控项出现nodata,通过设置触发器来触发报警或执行其他操作。open-falcon中则是有对指定指标进行赋值,即在出现数据终端时填充配置的值,一般配置-1,即配置一个该指标正常情况下不可能出现的数据。

在prometheus中目前还没有提供这种功能,因此我们只能从告警规则入手,希望通过告警规则的一些额外的配置,尽可能达到解决nodata的问题;或者进行其他一些告警后处理的工作;特殊场景下的一些处理。以下将从笔者的生产角度来描述是如何解决这类问题的。

1) 从规则入手

从规则入手解决nodata的一个核心问题就是如何获取全量数据,所谓全量数据就是能够覆盖nodata的数据,即告警规则中必定包含一个全量的指标,这个指标一般不会缺失。

这种情况下用到的主要prometheus的unless方法。

vector1 unless vector2

会产生一个新的向量,新向量中的元素由vector1中没有与vector2匹配的元素组成。

在创建规则的时候vector1一般表示全量指标,及一般不会有数据缺时的情况,例如对于服务器宕机告警,我们结合cmdb创建一个全量的指标,nodata_up。

nodata_up{ip="192.168.1.1"} 0nodata_up{ip="192.168.1.2"} 0nodata_up{ip="192.168.1.3"} 0

当up查询的时候返回的结果为

up{ip="192.168.1.1"} 1up{ip="192.168.1.2"} 1

即192.168.1.3目前没有数据,则通过

nodata_up unless on(ip) up or up !=1

即可以获得数据缺失的节点,这样可以达到当节点宕机时进行正常,当节点192.168.1.3没有数据时也可以触发告警。

nodata_up{ip="192.168.1.3"} 0

2) 告警后处理

如果有一定开发能力或者会简单脚本处理的,可以看看这一部分,这里主要是用于告警异常已经发生以后,由于数据缺失造成假恢复的情况,例如我们对服务器上内存使用率进行监控告警,并用指标sys_mem_used_percent表示内存使用率,并配置了如下的告警规则,当内存使用率高于90%时告警。

sys_mem_used_percent{ip="192.168.1.3"} > 90

当触发告警规则并告警以后,在中间的某一个时间段内如果出现sys_mem_used_percent指标没有数据,prometheus规则会认为告警已经恢复,因此会出现告警假恢复的情况。

prometheus的源码中是这样的:

func (r *alertingrule) eval(ctx context.context, ts time.time, query queryfunc, externalurl *url.url, limit int) (promql.vector, error) { res, err := query(ctx, r.vector.string(), ts){ ... for fp, a := range r.active { if _, ok := resultfps[fp]; !ok { // if the alert was previously firing, keep it around for a given // retention time so it is reported as resolved to the alertmanager. if a.state == statepending || (!a.resolvedat.iszero() && ts.sub(a.resolvedat) > resolvedretention) { delete(r.active, fp) } // 处理已经处于告警状态的告警转为恢复的状态 if a.state != stateinactive { a.state = stateinactive a.resolvedat = ts } continue } numactivepending if a.state == statepending && ts.sub(a.activeat) >= r.holdduration { a.state = statefiring a.firedat = ts } if r.restored.load() { vec = append(vec, r.sample(a, ts)) vec = append(vec, r.forstatesample(a, ts, float64(a.activeat.unix()))) } } ... }

r.ative表示前一次的告警,resultfps为最新的扫描的异常数据,由源码可清晰可见其处理的逻辑与实际表现是一致的。

我们的对待这个问题的一个处理逻辑是更改源码相关逻辑,但是这显然不是最佳选择。因此我们选择了另一种处理逻辑来处理这种假恢复的情况。

具体逻辑为,当出现恢复时,我们根据触发的规则从规则中提取出需要的指标,然后结合告警的标签,重新构造一维的查询表达式,然后去查询prometheus,判断是否存在数据,如果存在则为正常恢复,否则即为数据缺失造成的假恢复。

实现的大致代码如下:

func (a *arbitrator) nodata(alert promrule.alert, du time.duration) bool { metrics, er := lib.extractvectorsforgraph(a.expr) if er != nil { _ = level.warn(g.logger).log("module", "judge", "msg", er.error()) return false } excludekeys := map[string]struct{}{ "alertname": {}, "__name__": {}, } for k := range a.extlabels { excludekeys[k] = struct{}{} } for _, metric := range metrics { var matches []*labels.matcher for k, v := range alert.labels.map() { if _, ok := excludekeys[k]; !ok { matches = append(matches, &labels.matcher{ name: k, type: labels.matchequal, value: v, }) } } expr, er := lib.addexprtags(metric, matches) if er != nil { _ = level.warn(g.logger).log("module", "judge", "msg", er.error()) return false } if exist, _ := haslatestdata(expr); er == nil && !exist { _ = level.warn(g.logger).log("module", "judge", "msg", "nodata", "detail", expr) return true } } return false}

在告警环节加入代码判断

if alert.state == promrule.stateinactive && !alert.resolvedat.iszero() && time.now().sub(alert.resolvedat) > du { if a.nodata(alert, du) { return } }

本段仅为二次开发的核心代码,通过对告警消息的二次判断,去除nodata的假恢复情况。

3) 其他方法

这里主要是利用promethues的absent函数实现,

absent(v instant-vector)

如果传递给它的向量参数具有样本数据,则返回空向量;如果传递的向量参数没有样本数据,则返回不带度量指标名称且带有标签的时间序列,且样本值为1。 使用 absent 方法对告警中处理nodata的情况也是非常有用的。

对于某个确定的指标,如果确定应该有且仅有一组数据的时候,使用absent进行nodata告警。例如,如下配置可以实现对192.168.1.3在无数据时进行告警。

absent(up{ip="192.168.1.3"})

03 总结

通过prometheus本身的unless, absent 方法实现nodata问题的处理,unless的核心在于全量数据的确认。另外通过二开实现,主要对已经出现了告警,后期由于缺失数据造成的假恢复的情形的处置。当然了,对于nodata的处理方式可能还有一些好的方法,本文旨在为读者提供几种一般的处理方法,为解决nodata问题提供一些思路。

如果大家对运维技术有兴趣,欢迎入群交流,扫码添加好友,邀你入群!

prometheus通过什么协议采集指标 prometheus监控数据指标
作者:四川特产
四川特产