如何在普罗米修斯中优雅地避免被零除

时间:2017-11-01 13:55:45

标签: prometheus

有时您需要将一个指标除以另一个指标。

例如,我想像这样计算平均延迟:

rate({__name__="hystrix_command_latency_total_seconds_sum"}[60s])
/
rate({__name__="hystrix_command_latency_total_seconds_count"}[60s])

如果在指定时间段内没有活动,则分频器中的rate()变为0,分割结果变为NaN。 如果我对结果(avg()sum()或其他)进行一些汇总,则整个聚合结果将变为NaN

所以我在divider中添加了一个零检查:

rate({__name__="hystrix_command_latency_total_seconds_sum"}[60s])
/
(rate({__name__="hystrix_command_latency_total_seconds_count"}[60s]) > 0)

这会从结果向量中删除NaN。并且撕掉图表上的线条以撕碎。

0值标记为不活动的时段,以使图表再次连续:

rate({__name__="hystrix_command_latency_total_seconds_sum"}[60s])
/
(rate({__name__="hystrix_command_latency_total_seconds_count"}[60s]) > 0)
or
rate({__name__="hystrix_command_latency_total_seconds_count"}[60s]) > bool 0

这有效地将NaN替换为0,图表是连续的,聚合工作正常。

但结果查询有点麻烦,尤其是当您需要进行更多标签过滤并对结果进行一些聚合时。这样的事情:

avg(
    1000 * increase({__name__=~".*_hystrix_command_latency_total_seconds_sum", command_group=~"$commandGroup", command_name=~"$commandName", job=~"$service", instance=~"$instance"}[60s])
    /
    (increase({__name__=~".*_hystrix_command_latency_total_seconds_count", command_group=~"$commandGroup", command_name=~"$commandName", job=~"$service", instance=~"$instance"}[60s]) > 0)
    or
    increase({__name__=~".*_hystrix_command_latency_total_seconds_count", command_group=~"$commandGroup", command_name=~"$commandName", job=~"$service", instance=~"$instance"}[60s]) > bool 0
) by (command_group, command_name)

长话短说:有没有更简单的方法来处理分频器中的零?或者任何常见做法?

3 个答案:

答案 0 :(得分:4)

  

如果在指定时间段内没有活动,则分频器中的rate()变为0,分割结果变为NaN。

这是正确的行为,NaN就是你想要的结果。

  

聚合工作正常。

您无法汇总比率。你需要分别聚合分子和分母然后除。

所以:

   sum by (command_group, command_name)(rate(hystrix_command_latency_total_seconds_sum[5m]))
  /
   sum by (command_group, command_name)(rate(hystrix_command_latency_total_seconds_count[5m]))

答案 1 :(得分:1)

最后,我有一个针对特定问题的解决方案:

除以零会导致显示NaN-从技术上讲可以正常显示并且可以正确显示,但不能显示用户希望看到的内容(不满足业务要求)。

因此我进行了一些搜索,找到了grafana社区中的问题的“解决方案”:

max(YOUR_PROLEMATIC_QUERY, or vector(-1))包围您的问题价值。然后,附加的值映射将导致有用的输出。

(当然,您必须调整解决方案以解决您的问题...最小/最大... vector(42)/ vector(101)/ vector(...))

更新(1)

好的。然而。根据查询,似乎有些棘手。例如,我有另一个查询,由于除零导致NaN失败。上述解决方案不起作用。我必须用括号将查询括起来并添加 > 0 or on() vector(100)

答案 2 :(得分:0)

根据@eventhorizen 的回答,如果您有一个查询作为分母,有时会返回零,它可能会弄乱图表并在没有数据的情况下显示无穷大,您可以将结果限制在有效范围内。

例如,这个指标的输出应该在 0 到 1 之间,但是当没有数据时它也会产生 INFINITY:

(1/increase(SOMETIMES_ZERO_QUERY[1m]))

在这种情况下,您可以改为这样写,因此它显示 0 而不是大于 100 的值:

max((1/increase(SOMETIMES_ZERO_QUERY[1m]))<100 or on() vector(0))

或者如果你想要 1 作为无穷大:

max((1/increase(SOMETIMES_ZERO_QUERY[1m]))<100 or on() vector(1))