用 PromQL 计算 SLI 和 SLO

用 PromQL 查询出来过去一个月中用掉的 Error budget,然后展示当前的 SLI。效果如下图所示:

这个查询的难点在于,PromQL 查询出来的内容都是时序的值,比如 memory > 0.6 这个查询,查到的所有满足条件的时序的时间和值的对应。让查询的结果是时间,就需要一些技巧。

实现的思路是:

  1. 首先定义分钟级的 up 标准,即 SLO 的定义:1min中如何算是 up 的,如何算是 down 的;
  2. 然后写一个查询,可以查到在一个时间区间内,有多少个分钟是满足条件,up 的,有多少分钟是 down 的;
  3. 最后就可以得到实时的 SLI 结果;

想到有两个思路能实现。

第一个是利用 recording rules. 首先要定义一个 rule 叫做 job:sla_minute_up,这个 rule evaluation 的结果是当前的这一分钟是否满足 up 的所有条件。所以可能是一个很多 and 连起来的复杂表达式。

然后我们只要将所有 up 的分钟数加起来即可,即 sum_over_time(job:sla_minute_up[30d])。最后除以一个月中所有的分钟数:sum_over_time(job:sla_minute_up[30d]) / 30 * 24 * 60,就是最后得到的 SLI。

但是这里面有一个特别重要的地方,就是 sum_over_time 计算的是这段时间内所有出现过的点。比如,假设采集间隔是 15s,那么 up 这个 metric 在每分钟内会有 4 个点,sum_over_time(up[1m]) 正常情况的结果应该是 4. 所以说,使用这种方法的话,recording rules 的 evaluation internal 必须设置为 60s,来做到每分钟只有一个点。

这种方式实际的结果和计算过程绑定了, 所以并不是很好,下面这种方法更巧妙一些。

我们可以换一个思路,直接计算这段时间内满足条件的百分比,然后百分比乘以时间段,就是最终的 up time。

得到这个百分比,首先依然是需要分钟级的 up 定义。不过我们关心的并不是具体的 value,而是是否满足条件,即非是即否。使用 >bool 这个运算,可以将结果转化成 bool,如果满足条件,结果就是1,不满足,结果就是0. 这样,我们只需要计算这段时间内的平均值,就可以得到 SLI 的百分比了。比如说,如果全部是 up,那么结果全部都是1,那么所有时间内的平均是100%。如果出现了不是 up 的点,那么按照占用所有的点的百分比,也是对的。

这个方法就和 interval 无关了。interval 越小,数据点就多,精度会提高。interval 大,那么精度会损失。从客观来讲,表示的真实 SLI 在去掉精度后都是正确的。

如果要表示一天内的 SLI,假设 SLO 只有错误率的话,就可以用下面的查询:

也可以和 Grafana 配合,使用 Grafana 选中的时间区间:

 

参考资料:

  1. https://stackoverflow.com/questions/54292803/calculate-the-duration-in-which-a-prometheus-metric-had-a-certain-value
  2. https://docs.bitnami.com/tutorials/implementing-slos-using-prometheus

Leave a comment

您的电子邮箱地址不会被公开。 必填项已用*标注