PromQL 极简指南:把监控数据玩出花
从看懂 Grafana 图表,到自己写出 P95 延迟查询
当后端系统上线后,我们最怕的不是报错,而是两眼一抹黑。学会读懂和编写 PromQL,是你从“碰运气排障”跨越到“精准把脉系统状态”的关键一步。
🎯 为什么老是看不懂 PromQL?
每次打开 Grafana,想改一改某个图表的查询条件,总会看到类似这样一长串的“咒语”:
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
这是因为 Prometheus 存储数据的方式跟我们熟悉的 MySQL 关系型数据库完全不一样。它存的是时间序列数据(Time Series Data)。简单来说,它不是记下“某时某刻发生了一次请求”,而是记录“在这个时刻,请求的总数变成了 100”。
这套查询语言叫做 PromQL(Prometheus Query Language),它的核心逻辑是对时间轴上的数据点进行数学计算(求和、求速率、求分位数)。
🧠 核心概念:标签(Labels)与过滤器
在 PromQL 中,指标的维度是通过 标签(Labels) 来区分的。
http_requests_total{model="gpt-4o", status="200"}
这里 http_requests_total 是指标名称(一个一直在往上涨的计数器),而 {} 里面的内容就是过滤器。这句话的意思是:只给我看使用了 gpt-4o 并且状态码是 200 的请求总数。
这就像 SQL 里面的 WHERE model='gpt-4o' AND status='200'。
🔍 掌握这 5 把斧,搞定 90% 的监控需求
日常排查问题,你根本不需要背下几百个函数,只要搞懂下面这 5 个最高频的用法,就能看懂绝大多数的 Grafana 面板。
1. 计算 QPS(请求速率)—— rate()
只看请求总数没有意义,我们通常想知道的是**“每秒钟系统承载了多少请求”**。
rate(http_requests_total[1m])
[1m]:代表时间窗口(过去 1 分钟)。- 作用:计算过去 1 分钟内,这个计数器每秒平均增长了多少。
- 场景:画出早晚高峰的流量曲线。
2. 聚合求和(按维度分组)—— sum by
如果直接对包含几百个容器的系统求 rate,图表上会出现密密麻麻几百条线(每种标签组合都是一条线)。此时我们需要把它们合并。
sum by (client) (rate(http_requests_total[1m]))
- 作用:把结果按照
client这个标签进行分组,并把其他标签全丢掉、数值加起来。 - 等价于:SQL 中的
GROUP BY client。 - 场景:老板问你“最近一分钟各个业务线的 QPS 是多少?”,用它准没错。
3. 计算一段时间内的增量 —— increase()
有时候我们不关心每秒的速率,只想知道过去一段时间总共发生了多少次。
sum by (model) (increase(http_requests_total[24h]))
- 作用:计算过去 24 小时内,各个模型的请求量一共增长了多少次。
- 场景:查看今天全天的调用总量、或者刚刚过去的 5 分钟我测试了多少次接口。
4. 衡量真实的性能体验 —— histogram_quantile()
这是最有技术含量、也最让人头大的一个。为什么要用它?因为**“平均延迟”是一个撒谎的指标**。
假设 99 个请求都是 10ms,有 1 个请求卡了 10 秒。平均延迟看起来依然很低,但那个卡了 10 秒的用户体验极差。我们需要的是 P95 延迟(95% 的请求都在多少毫秒内完成的)。
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
http_request_duration_seconds_bucket:Prometheus 把延迟分成了很多个桶(比如 0.1秒的桶,0.5秒的桶),这个指标记录了落入每个桶的请求数量。le(less than or equal):就是“小于等于某耗时”的那个桶的标签。histogram_quantile(0.95, ...):基于这些桶的分布,估算出 95 分位数的具体时间。- 场景:评估后端系统的真实服务质量(SLA)。
5. 计算错误率比例
怎么知道系统现在的健康度?用错误请求速率除以总请求速率。
sum(rate(http_requests_total{status=~"5.."}[1m]))
/
sum(rate(http_requests_total[1m]))
status=~"5..":这里用到了正则表达式(=~),匹配所有以 5 开头的状态码(500, 502, 504)。- 场景:配合 Grafana 的报警功能,当错误率超过 1% 时自动推送到飞书/钉钉群。
⚠️ 新手避坑指南
- 别拿
rate()画总数图:rate算出来的是“每秒增量”,如果你的系统请求量很低,一分钟只有 2 个请求,那 rate(xxx[1m]) 画出来的线只有 0.03左右,你可能会以为数据丢了。看总增量用increase()。 - 时间窗口别设得比采集间隔还小:如果你的 Prometheus 每 15 秒抓取一次数据,你写
rate(xxx[10s])是算不出东西的,至少得涵盖两个数据点。 - 标签要克制:不要把随机生成的
x-request-id作为 Label 打到指标里!这会导致“高基数(High Cardinality)”问题,瞬间撑爆 Prometheus 的内存。
📝 总结
PromQL 并不是什么神秘的魔法。理解了它的时序特性,熟记 rate(看速率)、increase(看总量)、sum by(分组)和 histogram_quantile(看分位耗时),你就能在排查性能瓶颈、规划容量时拥有上帝视角。
下次再面对慢查询或者流量突增,不妨打开 Grafana 的 Explore 页面,敲下自己的第一行 PromQL 吧!