如何用PromQL基于指定指标计算月活跃用户(MAU)?
基于Prometheus计算月活跃用户(MAU)的PromQL实现
PromQL没有原生的COUNT(DISTINCT)函数,但可以通过组合现有函数实现与SQL等效的去重计数逻辑,同时支持生成随时间变化的MAU趋势图。
核心思路
要统计活跃用户,本质是找出在指定时间窗口内至少产生过一次请求(即指标有样本)的唯一user标签值,再对这些值进行计数。
1. 等效于SQL的指定时间范围MAU计算
对应你给出的SQL语句:
SELECT COUNT(DISTINCT user) FROM ServiceLevelIndicator_milliseconds_count WHERE time BETWEEN @from AND @to
PromQL写法如下:
count(count_over_time(ServiceLevelIndicator_milliseconds_count[@from:@to]) by (user))
解释:
count_over_time(指标[时间范围]):统计每个时间序列在指定时间范围内的样本数量,只要用户有活跃行为,这个值就大于0。by (user):按user标签分组,得到每个用户在时间范围内的总样本数(仅保留有活跃记录的用户)。- 外层
count():统计分组后的用户数量,即去重后的活跃用户数。
你需要将@from和@to替换为具体时间(比如2024-01-01T00:00:00Z到2024-01-31T23:59:59Z),或相对时间(比如1month ago到now())。
2. 生成随时间变化的MAU趋势图
如果要展示每个时间点往前30天的活跃用户数(即滚动MAU),只需将时间范围改为滑动窗口:
count(count_over_time(ServiceLevelIndicator_milliseconds_count[30d]) by (user))
解释:
当在Grafana等工具中绘制图表时,Prometheus会根据图表的时间步长,自动计算每个时间点对应的过去30天窗口内的活跃用户数,最终生成连续的MAU趋势曲线。
3. 处理额外标签的注意事项
如果ServiceLevelIndicator_milliseconds_count带有其他无关标签(比如instance、service),同一个用户可能会被这些标签拆分出多个时间序列,导致重复统计。此时需要先聚合掉无关标签:
count(count_over_time(sum without (instance, service)(ServiceLevelIndicator_milliseconds_count)[30d]) by (user))
用sum without(标签名)将同一用户在不同实例/服务下的请求合并,避免重复计数。
限制说明
- 依赖指标的样本完整性:只有用户产生请求时,
ServiceLevelIndicator_milliseconds_count才会生成样本,无请求的用户不会被统计。 - 性能考量:如果用户量极大(百万级以上),按
user分组会消耗大量内存,此时可以考虑用近似计数方案(比如结合topk),但会牺牲一定准确性。
内容的提问来源于stack exchange,提问作者Xavier John
相关产品推荐
相关产品推荐

