【问题标题】:Correctly detecting a change in a Prometheus count metric正确检测 Prometheus 计数指标的变化
【发布时间】:2019-09-09 18:06:07
【问题描述】:

我尝试编写一个 PromQL 查询来检测计数指标的变化。

我的抓取间隔是 15 秒。

我这样查询指标:

http_server_requests_seconds_count{outcome!="REDIRECTION",outcome!="SUCCESS"}

它显示了所有http_server_requests 中有多少没有重定向且未成功。

我尝试使用此指标编写警报表达式如下所示:

sum by(service, method, outcome, status, uri) (
  rate(
    http_server_requests_seconds_count{
      outcome!="REDIRECTION",
      outcome!="SUCCESS"
    }[1m]
  )
) * 60

我的想法是,当发生变化时,[1m] 乘以 60 秒的速率将是 1,但据我所知,我得到的是 2

这些图表清楚地表明了这一点:

上图是求和表达式,下图是服务器请求计数的变化。当底部图计数 +1 时,顶部图也应暂时上升到 1(但实际上它上升到 2)。

我做错了什么?我是不是误会了什么?当发生更改时,如何编写一个查询以提供值 1?我应该期望能够编写这样的查询吗?

谢谢!

【问题讨论】:

    标签: prometheus promql


    【解决方案1】:

    这是因为 Prometheus 优先考虑范围的一致定义,而不是准确性。 IE。它总是将范围定义为(包含)区间 [now() - range, now()] 内的所有样本。这个定义对仪表非常有意义:如果您想计算一个时间范围等于步长的avg_over_time(),您希望每个输入样本都包含在恰好一个输出样本的计算中。

    但计数器并非如此。在时间范围等于步长的情况下,一个输入值(即两个连续样本之间的增量)基本上被丢弃。 (有关更多详细信息,请参阅 Prometheus 问题 #37463806。)为了弥补它丢弃的数据,Prometheus 使用外推法来调整计算结果。

    这意味着如果(如您的情况)您使用的时间范围是您的抓取间隔的 2 倍(1m 范围为 30s 抓取间隔),Prometheus 将(平均)在每个范围内找到 2 个样本,但这两个样本所涵盖的实际时间范围将在30s 左右。因此,Prometheus 将通过将值加倍来帮助将速率推断为请求的1m。因此,结果是 2 而不是预期的 1。您还会注意到,由于连续样本之间的一些增加被丢弃(即使没有样本),并不是您的计数器中的所有增加都显示在您的 rate() 图表中。 (即rate() 中没有对应于第三次计数器增加的跳转。如果您在不同时间刷新,不同的增加会出现和消失。Grafana 通过始终将请求的范围与步骤对齐来“解决”后者,因此始终丢失相同的增加。)

    Prometheus 开发人员建议的解决方案是计算更长持续时间的费率。但所做的只是减少误差(你会得到 1.5 与 3x 范围,1.33 与 4x 范围,1.25 为 5x 范围等),永远不会摆脱它。普罗米修斯的推断被平稳地增加计数器隐藏得很好,但像你自己的计数器一样突出,很少增加。)

    解决此问题的唯一解决方法(没有修复 Prometheus,为此我已提交 PR 并正在维护 a fork)是对 Prometheus 的 rate() 实现进行逆向工程。 IE。假设抓取间隔为30s,类似rate(foo[1m]) 的表达式应替换为:

    rate(foo[90s]) * 60 / 90
    

    或更笼统地说(注意括号内的表达式需要是时间文字,不能是计算)

    rate(foo[intended_range + scrape_interval]) * intended_range / (intended_range + scrape_interval)
    

    之所以有效,是因为intended_range + scrape_interval 范围将为您提供足够的样本来覆盖intended_range 的增加,这正是您想要的。但是随后您必须撤消 Prometheus 的推断引入的变化,因此随之而来的乘法和除法。这是一个丑陋的黑客,取决于你知道你的抓取间隔并将其硬编码到你的记录规则和/或 Grafana 查询中。

    请注意,无论您使用哪种方法,您都可能不会得到正好为 1 的值。由于服务、网络和内部 Prometheus 延迟,样本通常不会以毫秒为单位对齐,因此每秒的增长率会略低于或略高于预期值。

    【讨论】:

      【解决方案2】:

      这里是计算计数器指标正确变化的替代方法:

      max_over_time(http_server_requests_seconds_count{outcome!="REDIRECTION",outcome!="SUCCESS"}[1m])-min_over_time(http_server_requests_seconds_count{outcome!="REDIRECTION",outcome!="SUCCESS"}[1m])
      

      我花了一段时间才弄清楚的另一件事是,在绘制上述内容时,需要确保绘图的分辨率不大于刮擦间隔。否则,您希望看到的部分或全部尖峰将不会显示。

      【讨论】:

        【解决方案3】:

        您需要使用changes() 函数。如果匹配的计数器在最后一分钟发生变化,则以下查询将返回非零值(请参阅查询中的[1m]lookbehind 窗口):

        changes(http_server_requests_seconds_count{outcome!="REDIRECTION",outcome!="SUCCESS"}[1m])
        

        至于意外的rate()increase() 结果-请阅读this commentthis article

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-02
          • 2019-09-29
          • 1970-01-01
          • 2011-09-29
          • 2020-11-09
          • 2021-01-01
          • 2017-09-25
          相关资源
          最近更新 更多