如何基于多日同时间段生成均值与标准差(PromQL实现)
基于Prometheus实现同时间段历史均值与标准差的异常检测
你的需求完全可以通过PromQL的内置函数和offset特性实现,核心是对齐历史同时间段的数据,再结合统计函数计算均值与标准差,进而识别异常。
步骤1:计算历史同时间段的小时均值
方法1:枚举历史天数(直观易理解)
直接枚举过去14天的同时间段数据,用avg()求平均:
groups: - name: my_alert_rules rules: # 记录过去14天同一小时的错误率均值 - record: error_rate:1h:avg_over_14d expr: avg( sum(rate(error_count{some_label="some_value"}[1h])) offset 1d, sum(rate(error_count{some_label="some_value"}[1h])) offset 2d, sum(rate(error_count{some_label="some_value"}[1h])) offset 3d, sum(rate(error_count{some_label="some_value"}[1h])) offset 4d, sum(rate(error_count{some_label="some_value"}[1h])) offset 5d, sum(rate(error_count{some_label="some_value"}[1h])) offset 6d, sum(rate(error_count{some_label="some_value"}[1h])) offset 7d, sum(rate(error_count{some_label="some_value"}[1h])) offset 8d, sum(rate(error_count{some_label="some_value"}[1h])) offset 9d, sum(rate(error_count{some_label="some_value"}[1h])) offset 10d, sum(rate(error_count{some_label="some_value"}[1h])) offset 11d, sum(rate(error_count{some_label="some_value"}[1h])) offset 12d, sum(rate(error_count{some_label="some_value"}[1h])) offset 13d, sum(rate(error_count{some_label="some_value"}[1h])) offset 14d )
方法2:子查询自动对齐(灵活易维护)
先记录每小时错误率,再按小时分组计算14天内的均值:
groups: - name: my_alert_rules rules: # 记录每小时的错误率 - record: error_rate:1h expr: sum(rate(error_count{some_label="some_value"}[1h])) # 按小时聚合过去14天的均值 - record: error_rate:1h:avg_over_14d expr: avg_over_time(error_rate:1h[14d]) by (hour())
by (hour())会自动把过去14天中同一小时的所有数据聚合,完美对齐当前时间的对应时段。
步骤2:计算历史同时间段的标准差
用stddev_over_time函数实现,和均值逻辑一致:
# 记录过去14天同一小时的错误率标准差 - record: error_rate:1h:stddev_over_14d expr: stddev_over_time(error_rate:1h[14d]) by (hour())
如果用枚举法,把avg()替换成stddev()即可。
步骤3:编写告警规则
基于均值和标准差设置告警条件,比如当前错误率超过均值+2倍标准差时触发:
- alert: HighErrorRateAnomaly expr: | sum(rate(error_count{some_label="some_value"}[1h])) > error_rate:1h:avg_over_14d + 2 * error_rate:1h:stddev_over_14d for: 5m labels: severity: critical annotations: summary: "异常错误率告警" description: "当前错误率: {{ $value }}, 历史同小时均值: {{ $values.error_rate:1h:avg_over_14d }}, 标准差: {{ $values.error_rate:1h:stddev_over_14d }}"
关键优化建议
- 由于错误率和活跃用户数成正比,建议先将错误率归一化:
sum(rate(error_count[1h])) / sum(rate(active_users[1h])),再做历史统计,消除用户量波动的干扰。 for: 5m用于过滤瞬时波动的误告警,可根据业务实际调整时长。- 确保Prometheus存储保留至少14天的历史数据,否则子查询会丢失数据。
内容的提问来源于stack exchange,提问作者Sam Niconi
相关产品推荐
相关产品推荐

