rate/increase函数计算结果中为何出现异常的巨大数值?
rate与increase仅适用于递增类型的指标数据,即指标数值随时间增长逐渐增大。此处基于Prometheus Engine源码解释异常原理,可参考源码。
下面的截图中展示了rate与increase函数针对时间窗口内数据点的详细计算过程:先计算首位两个数值的差值resultFloat,然后开始遍历余下的数值点,若出现数值下降时则会将前一个数值prevValue累加到值resultFloat中,从而造成最终的结果值变得异常巨大。
排查方式:
使用PromQL查询先确定是否出现数值下降,首先将时间筛选框缩小到出现异常的时间段,并执行以下的PromQL语句(需将“xxxx_metric”更换为真实指标数据),若此查询的结果集中存在数据点则能够说明出现了“数值下降”的现象。
Query语句:(xxxx_metric{} - xxxx_metric{} offset 1s) < 0 Step 参数:1s
针对出现异常数值的时间线,可使用SQL方式将原始的异常数值点查询出来,例如:
* | select *, from_unixtime(__time_nano__/1000000.0) from "时序库名.prom" where __name__='指标名' and element_at(__labels__, '用于筛选的某个labelKey')='用于筛选的某个labelValue' order by __time_nano__ // 建议在SQL中添加多个 element_at 函数来进一步缩小时间线范围。
SQL结果集中已按时间戳排序,可直接观察到已写入的原始脏数据点。
已写入时序数据,使用PromQL为什么查不到数据?
首先确认下述两种场景是否存在问题。
场景一:PromQL语法是否正确,时序库的查询框中会自动提示语法解析情况,若存在问题请按照提示修改;
场景二:参见下面的截图进入时序库的“自定义分析”页面,并执行下述的SQL确认对应时间段内有无数据。
此SQL中的
__name__
字段表示MetricName。* | select * from "MetricStore名字.prom" where __name__ = 'demo_api_request_duration_seconds_bucket'
上述两种场景检查没有问题,则可能是Prometheus计算引擎中的特殊的“选点”逻辑和“lookback-delta”机制造成的。
Prometheus计算引擎提供了一种名为PromQL的查询语言,该语言在执行计算时不一定会将全部数据点都纳入计算点,在执行计算前实际还存在一个“选点”过程。PromQL语法所包含的所有算子、函数、运算符在数据“选点”这个流程上可分成两类:带“[1m]、[1h]”等操作符的RangeVectorSelector 和 InstantVectorSelector。
下面分别列举了几项包含两种VectorSelector的PromQL示例。
RangeVectorSelector:
rate(http_requests_total[5m])
delta(http_requests_total[5m])
count_over_time(http_requests_total[5m])
InstantVector:
http_requests_total
absent(http_requests_total)
count(http_requests_total)
RangeVectorSelector的“选点”流程是将“[xx]”
操作符所覆盖时间范围内的数据点都纳入计算,如下图,操作符“count_over_time ( up [30s] )”
表示每次计算时都会将当前时间点及往前30秒的数据点都纳入到计算中。
PromQL中的“lookback-delta”
机制仅对InstantVectorSelector有效,在“选点”时会根据“lookback-delta”
参数值大小往前找特定时间区间,并将最近时间点的数据点作为当前时间点的数据值。在绝大多数情况下,原始数据的写入时间点和查询时间点是没有对齐的,在“选点”时会往前回溯n分钟(SLS默认3分钟,可通过自定义参数调整,请参见时序指标查询API),并将最近的数据点作为当前时间点的数据。
下图示例中,查询的startTime为09分28秒,该时间点不存在原始数据点,则会往前找到06分28秒,而这段时间都没有写入数据,则表示09分28秒没有选取到数据点。同理,09分43秒则选取了09分40秒的数据点、09分58秒选取了09分55秒的数据点。
由于该机制的特殊性,在“选点”时还存在一种特殊场景:在已经不存在数据的时间点,使用PromQL却查出了数据。下图示例中,10分00秒后已经不存在数据,但10分13秒、10分28秒、10分43秒、12分58秒等时间点都因为“lookback-delta”
的机制往前回溯3分钟并选取到了10分00秒的数据点。
两类VectorSelector的“选点”逻辑是完全不一致的,而查不到数据通常也和这两类“选点”逻辑有关系,下面分别对两类逻辑查不到数据的可能性场景做分析。
RangeVectorSelector
操作符
“[xx]”
中表示的时间区间较小,而运算的步长“step”
参数较大,可能导致单次计算前的“选点”流程并没有选取到数据点。例如,原始写入的指标数据
“up”
为每小时(整点)一个点,查询参数为:startTime: 10:30:00 endTime : 18:30:00 step : 1h query : count_over_time(up[10m])
预期会返回7个数据点,而实际的查询结果为空,原因分析:PromQL计算逻辑会从startTime开始每间隔step执行一次计算,即在“11:30:00、12:30:00、13:30:00、14:30:00、15:30:00、16:30:00、17:30:00、18:30:00”这些时间点都会计算一次计算,但每次计算前的“选点”仅选取了近10分钟范围内所有点,致使每次“选点”都没有选到数据点。
InstantVectorSelector
“lookback-delta”
参数较小,而运算的步长“step”
参数较大,可能导致单次计算前的“选点”流程没有找到最近的数据点。例如,原始写入的指标数据
“up”
为每小时(整点)一个点,查询参数为:startTime: 10:30:00 endTime : 18:30:00 step : 1h query : count(up)
Prometheus中默认的
“lookback-delta”
参数为5分钟,SLS时序库中默认为3分钟。在每次计算前的“选点”仅会往前找3分钟,即在“11:30:00、12:30:00、13:30:00、14:30:00、15:30:00、16:30:00、17:30:00、18:30:00”这些时间点都近会往前找3分钟,并将时间最近的数据点作为当前时刻的数据值。由于原始数据的分布较稀疏,上述几次“选点”都没有找到数据点,致使最后的计算结果同样为空。
解决方案
调整查询参数中的
startTime
、endTime
和step
参数,将参数与写入时间点对齐后,就能够选取到写入时间点的数据。例如,下面的查询会返回7个数据点。在实际的应用场景中,指标数据点采集时刻并不是非常规整的,并且查询时也并不会刻意去对齐参数,所以不推荐使用此方案。
startTime: 10:00:00 endTime : 18:00:00 step : 1h query : count(up)
调小step参数,例如我们将step参数设置为3分钟,以上述InstantVectorSelector场景为例,一定有多次“选点”能够选取原始的数据点。此方案是让“选取”流程变得更密集,以确保能够选取到原本较稀疏的数据点。
调大“lookback-delta”参数或者调大“[xx]”操作符的数值,调整此两项参数则是通过扩大“选点”的时间区间,将尽可能多的数据点纳入选择范围。
特定时间点之后已不再写入数据,为什么使用PromQL仍能查出在该时间点之后的数据?
原因与Prometheus计算引擎中的“lookback-delta”机制有关,请参见“lookback-delta”机制。
为什么查询结果中数据点的时间与写入时间不一致?
原因与Prometheus计算引擎中的“lookback-delta”机制有关,请参见“lookback-delta”机制。
针对相同时间范围,为什么最新执行结果与历史执行结果不一致?
存在两种可能性:
如果时间框选择的是“相对时间”模式,可能是 start 和 end 参数变化后,计算引擎在执行“lookback-delta”操作时选取到的数值点发生了变化,从而造成前后两次结果不一致。此现象符合Prometheus标准,属于正常情况。
如果前后两次执行相隔较长且查询的时间范围也一致,可能是历史执行时,预期内将参与计算的数据还未到SLS侧(写入数据存在延迟)。前后两次参与计算的数据不一致造成了结果不一致。若属于此类现象,可在PromQL语句中使用 offset 语法将查询区间往前平移一段时间,去除因写入延迟造成的结果错误。
单次Query计算资源超限,请求被拒绝
如果Query请求返回的错误中包含了“too many time Series or items,xxxxxx” 、“too many time Series or items in parallelMaster node,xxxxx”等文本提示,则说明该次Query读取了很大的数据量,已触发了计算层的内存限制。
解决方案
缩小查询区间。
若强依赖于上述时间范围的执行时序计算,建议开启并发计算,参考并发计算配置即可。
vector cannot contain metrics with the same labelset错误
原因一:
__labels__
字段值中的LabelName不符合字母序。写入MetricStore的
__labels__
字段由多组Label (LabelName#$#LabelValue)组成,且所有Label之间使用竖线(|)连接。在时序标识中,要求所有Label按照LabelName的字母序排序。更多信息,请参见时序标识。当
__labels__
字段值中的LabelName不符合字母序时,会出现该错误。您可以通过如下SQL语句确认__labels__
字段值中的LabelName是否按照字母序排序。* | select * from ( select __labels__, array_join(array_sort(split(__labels__, '|')), '|') as rightLabels from "MetricStore名字.prom" where __name__!='' ) where __labels__ != rightLabels
原因二:
__labels__
字段值中存在LabelValue为空问题。在Prometheus Engine中,LabelValue为空的Label会被视作无效。Prometheus Engine执行计算时会删除无效Label,因此出现该错误。您可以通过下述步骤确认
__labels__
字段值中是否存在LabelValue为空问题。缩小查询时间范围,定位到出现此错误的大致时间区间。
执行如下SQL语句。
* | select __labels__ from "MetricStore名字.prom" where __name__!='' and regexp_like(__labels__, '.*#\$#\|.*|.*#\$#$')
如果有返回结果,则表示存在LabelValue为空问题。建议修正数据上报端代码逻辑,删除无效Label。
PromQL查询时缺失Label信息,但原始数据中存在该Label
__labels__
字段值中的LabelName未按照字母序排序时会出现该问题。您可以通过如下SQL语句确认__labels__
字段值中的LabelName是否按照字母序排序。
* | select * from (
select __labels__, array_join(array_sort(split(__labels__, '|')), '|') as rightLabels from "MetricStore名字.prom" where __name__!=''
) where __labels__ != rightLabels
PromQL中涉及by/without计算时,结果不符合预期
__labels__
字段值中的LabelName未按照字母序排序时会出现该问题。您可以通过如下SQL语句确认__labels__
字段值中的LabelName是否按照字母序排序。
* | select * from (
select __labels__, array_join(array_sort(split(__labels__, '|')), '|') as rightLabels from "MetricStore名字.prom" where __name__!=''
) where __labels__ != rightLabels
指标探索中没有数据
可能原因是默认查询时间范围内没有数据。
在选择查询时间范围时,确保该时间范围内存在数据。
使用指标探索功能时,为保证响应速度,系统默认查询范围为最近5分钟。
在控制台中,查询到的时序数据缺失较多时间线
在日志服务控制台的MetricStore查询分析页面中执行查询时,存在limit参数,该参数会限制SQL查询或PromQL查询的返回数据的数量。建议适当调大该参数。
PromQL计算结果中存在Warning信息
可能原因是在拉取原始数据时,因Shard读取能力上限问题,未将该时间段内的数据读取完整。建议缩小查询时间范围或者分裂Shard提升整体吞吐能力。
exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)错误
在Prometheus中,限制每条时间线最大存在11000个数据点,即 (endTime - startTime) / step
的值最大为11000。建议缩小查询区间或者调大step参数。
- 本页导读 (1)
- rate/increase函数计算结果中为何出现异常的巨大数值?
- 排查方式:
- 已写入时序数据,使用PromQL为什么查不到数据?
- 解决方案
- 特定时间点之后已不再写入数据,为什么使用PromQL仍能查出在该时间点之后的数据?
- 为什么查询结果中数据点的时间与写入时间不一致?
- 针对相同时间范围,为什么最新执行结果与历史执行结果不一致?
- 单次Query计算资源超限,请求被拒绝
- vector cannot contain metrics with the same labelset错误
- PromQL查询时缺失Label信息,但原始数据中存在该Label
- PromQL中涉及by/without计算时,结果不符合预期
- 指标探索中没有数据
- 在控制台中,查询到的时序数据缺失较多时间线
- PromQL计算结果中存在Warning信息
- exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)错误