📊 PromQL 核心语法解析
资源推荐:
官方文档:https://prometheus.io/docs/prometheus/latest/querying/basics/
PromQL 备忘单:https://prometheus.io/docs/prometheus/latest/querying/examples/
一、PromQL 是什么?
1️⃣ 一句话理解
PromQL = 从「时间序列指标」里筛选、计算、聚合数据的语言
它解决的问题:
-
指标太多,怎么筛?
-
Counter 怎么算「每秒速率」?
-
多台机器怎么求总和/平均?
-
怎么算 P95/P99 延迟?
-
告警条件怎么写?
2️⃣ 查询流程
输入查询 → 解析语法 → 匹配时间序列 → 执行计算 → 返回结果
↓ ↓ ↓ ↓ ↓
PromQL 语法检查 标签匹配器 聚合/函数 数据点
3️⃣ PromQL ≠ SQL(重要区别)
| 对比 | SQL | PromQL |
|---|---|---|
| 操作对象 | 表、行 | 时间序列 |
| 核心维度 | 行 | 时间 + 标签 |
| 查询结果 | 静态结果集 | 随时间变化的向量 |
👉 PromQL 操作的是:时间序列集合
二、数据模型:时间序列 = 指标 + 标签
http_requests_total{method="POST", handler="/api", status="200", instance="10.0.0.91:9100"} 1625097600 1500
↑ ↑ ↑ ↑ ↑ ↑ ↑
指标名称 标签名 标签值 标签名 标签值 时间戳 值
- 指标名(metric):
http_requests_total - 标签(label):
method / status / instance - 样本值:随时间变化的数值
📌 PromQL 的本质:对一堆带标签的时间序列做过滤、计算、聚合
三、PromQL 的 4 种数据类型
写 PromQL 前,脑子里必须知道:当前表达式返回的是什么类型
| 类型 | 说明 | 示例 | 特点 |
|---|---|---|---|
| 瞬时向量 | 某一时间点的时间序列 | node_cpu_seconds_total |
多条序列 + 单值 |
| 区间向量 | 一段时间内的时间序列 | node_cpu_seconds_total[5m] |
多条序列 + 多值 |
| 标量 | 单一数值 | 3.14 |
无时间戳 |
| 字符串 | 字符串 | "hello" |
仅用于标签 |
选择器类型对比
# 1. 瞬时向量选择器 - 最新值
http_requests_total
http_requests_total{method="GET"}
http_requests_total{method!="GET"}
# 2. 区间向量选择器 - 一段时间内的值
http_requests_total[5m]
http_requests_total[1h]
# 3. 偏移修饰符 - 查询历史数据
http_requests_total offset 1d
rate(http_requests_total[5m] offset 1h)
四、标签过滤:缩小数据范围
4.1 四种匹配操作符
| 符号 | 含义 |
|---|---|
= |
精确匹配 |
!= |
不等于 |
=~ |
正则匹配 |
!~ |
正则不匹配 |
4.2 实战示例
# 1. 多标签精确匹配
http_requests_total{method="GET", status="200"}
# 2. 正则表达式匹配
node_cpu_seconds_total{instance=~"prod-.*"} # 匹配prod开头
http_requests_total{version=~"v1\\..*"} # 匹配v1.x版本
# 3. 排除特定环境
http_requests_total{env!~"test|dev"} # 排除测试和开发环境
# 4. 查找空标签
http_requests_total{instance=""} # instance标签为空的序列
# 5. 转义特殊字符
{host=~"web\\d+\\.example\\.com"} # 匹配包含点的域名
📌 生产建议:尽量先用 label 缩小数据集,再做计算
五、核心函数详解
5.1 速率函数(计数器专用)
⭐ rate() - 核心中的核心
# 计算过去5分钟内,平均每秒增长率
rate(http_requests_total[5m])
# 生产环境最佳实践
rate(node_network_receive_bytes_total[2m]) * 8 # 转换为比特率
rate(container_cpu_usage_seconds_total[1m]) # CPU使用率
# 注意事项:
# 1. 区间至少是抓取间隔的2倍(建议4倍)
# 2. 对于变化剧烈的指标,使用 irate()
irate() - 瞬时速率
# 基于最后两个数据点计算瞬时速率
irate(http_requests_total[5m])
# 适用场景:
# 1. 快速变化的计数器
# 2. 需要检测瞬时峰值
# 3. 短时间窗口的监控
# 4. 排查突发问题,不适合报警
# 对比示例:
# rate()[5m]: 过去5分钟的平均每秒请求数
# irate()[5m]: 基于最后两个点的瞬时每秒请求数
increase() - 区间总增量
# 计算指定时间范围内的总增长量
increase(http_requests_total[1h])
# 实际应用:
# 计算每小时请求总数
increase(http_requests_total[1h])
# 计算每天的增量
increase(node_network_receive_bytes_total[24h])
5.2 变化量函数(Gauge专用)
delta() - 绝对变化量
# 计算指标在一段时间内的"绝对变化量"
delta(memory_usage_bytes[5m])
# 实际应用:
# 内存是否持续上涨
delta(container_memory_usage_bytes[10m]) > 0
# 队列积压变化
delta(queue_length[5m])
# 正数:积压增加
# 负数:消费速度大于生产
# 适用指标:
✅ 非计数器(Gauge):内存使用量、CPU load、连接数、队列长度
❌ 不适合 Counter(会因重启重置)
deriv() - 变化率
# 计算变化速率(单位变化/秒)
deriv(node_temperature_celsius[10m])
5.3 时间窗口聚合函数
over_time 系列
max_over_time(cpu_usage[5m]) # 这段时间的最大值
avg_over_time(node_memory_MemAvailable_bytes[5m]) # 这段时间的平均值
min_over_time(free_disk_space[1h]) # 最小值
sum_over_time(network_bytes[10m]) # 总和
count_over_time(up[5m]) # 计数
quantile_over_time(0.95, latency[5m]) # 分位数
📌 生产口诀:
Counter 看 rate / increase,Gauge 看 delta / over_time
六、聚合函数:多维度数据汇总
6.1 基础聚合
# 按维度聚合
sum by (instance, job) (rate(http_requests_total[5m]))
avg by (namespace) (container_memory_usage_bytes)
max by (device) (node_filesystem_size_bytes)
min by (env) (application_response_time_seconds)
# 排除维度聚合
sum without (instance) (rate(http_requests_total[5m]))
6.2 统计聚合
# 计数
count by (job) (up == 1) # 统计每个job的正常实例数
# 分位数(常用于直方图)
histogram_quantile(0.95,
rate(http_request_duration_seconds_bucket[5m])
)
# 标准差和方差
stddev by (instance) (node_cpu_seconds_total)
stdvar by (service) (request_latency_seconds)
6.3 TopK/BottomK
# 找出前5个CPU使用率最高的实例
topk(5, rate(container_cpu_usage_seconds_total[5m]))
# 找出内存使用最低的3个Pod
bottomk(3, container_memory_usage_bytes)
# 注意:返回的是原始时间序列,不是聚合值
6.4 聚合最佳实践
📌 生产口诀:
先算 rate,再聚合
七、数学运算
7.1 基本算术运算
# 四则运算
http_requests_total * 2
http_errors_total / http_requests_total * 100 # 错误率百分比
# 单位转换示例
# 字节转兆字节
node_memory_MemFree_bytes / 1024 / 1024 # MiB
node_memory_MemFree_bytes / (1024^2) # 同上,更优雅
# 网络速率转换(字节/秒 转 比特/秒)
rate(node_network_receive_bytes_total[2m]) * 8
7.2 逻辑运算
| 运算符 | 含义 |
|---|---|
and |
与 |
or |
或 |
unless |
排除 |
7.3 比较运算
# 告警规则常用模式
up == 0 # 实例宕机
node_memory_MemFree_bytes < 100 * 1024 * 1024 # 内存不足100MB
rate(http_5xx_errors_total[5m]) > 0.05 # 5xx错误率超过5%
# 布尔结果转换为数值(用于聚合)
(up == 1) * 1 # 正常实例返回1,宕机返回0
7.4 数学函数
abs(temperature - 25) # 绝对值
sqrt(node_memory_MemFree_bytes) # 平方根
ceil(node_cpu_usage) # 向上取整
floor(node_cpu_usage) # 向下取整
round(node_cpu_usage, 0.01) # 四舍五入
clamp_max(node_cpu_usage, 100) # 限制最大值
clamp_min(node_cpu_usage, 0) # 限制最小值
八、标签操作
8.1 标签操作函数
label_replace() - 标签替换
# 添加或修改标签
label_replace(
http_requests_total,
"new_label", # 新标签名
"$1-$2", # 新标签值($1, $2 引用正则分组)
"instance", # 源标签
"(.*):(.*)" # 正则表达式
)
# 实际应用:从 instance 中提取主机名和端口
label_replace(
node_cpu_seconds_total,
"hostname",
"$1",
"instance",
"([^:]+):.*"
)
label_join() - 标签连接
# 连接多个标签值
label_join(
node_cpu_seconds_total,
"full_instance", # 新标签名
"-", # 分隔符
"instance", "job" # 要连接的标签
)
# 示例结果:
# instance="10.0.0.91:9100", job="node" → full_instance="10.0.0.91:9100-node"
8.2 标签匹配问题
标签不一致?用 on / ignoring
# 如果标签不一致,会算不出来
A / B
# 指定匹配标签
A / on(instance) B
# 忽略标签
A / ignoring(cpu) B
📌 这是 PromQL 最容易劝退新手的点
group_left / group_right(多对一关联)
A * on(instance) group_left(role) B
常见场景:
- 指标 + 元数据关联
- pod → node 关联
九、生产级常见 PromQL 示例
9.1 系统资源监控
CPU 使用率
# 方法1:基于 node_cpu_seconds_total
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[2m])) * 100)
# 方法2:更精确的计算
sum by(instance)(rate(node_cpu_seconds_total{mode!="idle"}[2m]))
/ count by(instance)(node_cpu_seconds_total{mode="system"}) * 100
内存使用率
# 内存使用百分比
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes)
/ node_memory_MemTotal_bytes * 100
# 内存使用量(GB)
(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / 1024^3
# Mem使用率(简化)
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
磁盘使用率
# 按挂载点计算使用率
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_free_bytes{mountpoint="/"})
/ node_filesystem_size_bytes{mountpoint="/"} * 100
# 排除特定文件系统类型
node_filesystem_size_bytes{fstype!="tmpfs",fstype!="rootfs"}
9.2 服务健康监控
实例存活状态
# 基础存活检查
up
# 按job统计存活实例数
count by(job) (up == 1)
# 存活率计算
avg by(job) (up) * 100
# 检测最近重启的实例
time() - process_start_time_seconds < 300 # 5分钟内重启的
HTTP 服务监控
# 请求速率(按状态码分类)
sum by(status_code) (rate(http_requests_total[5m]))
# 错误率(4xx和5xx)
sum(rate(http_requests_total{status=~"4..|5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
# 第95百分位延迟
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
9.3 业务指标监控
QPS(每秒查询数)
# 总QPS
sum(rate(http_requests_total[5m]))
# 按接口分组
sum by(endpoint) (rate(http_requests_total[5m]))
# 成功请求QPS
sum by(endpoint) (rate(http_requests_total{status_code=~"2.."}[5m]))
业务成功率
# 交易成功率
sum(rate(transactions_total{result="success"}[5m]))
/ sum(rate(transactions_total[5m])) * 100
# API成功率(排除客户端错误)
sum(rate(api_calls_total{status_code!~"4.."}[5m]))
/ sum(rate(api_calls_total[5m])) * 100
9.4 容量规划预测
磁盘空间预测
# 预测磁盘何时写满(基于过去6小时趋势)
predict_linear(node_filesystem_free_bytes{mountpoint="/"}[6h], 3600 * 24 * 7)
# 计算剩余天数
node_filesystem_free_bytes{mountpoint="/"}
/ ((node_filesystem_free_bytes{mountpoint="/"} - predict_linear(node_filesystem_free_bytes{mountpoint="/"}[6h], 3600)) / 3600 / 24)
内存增长趋势
# 内存使用增长趋势
deriv(
node_memory_MemUsed_bytes[1h]
) # 单位:字节/秒
# 转换为MB/小时
deriv(node_memory_MemUsed_bytes[1h]) * 3600 / 1024 / 1024
十、Histogram & 延迟分析(进阶但常用)
10.1 Histogram 结构回顾
指标通常是:
*_bucket*_sum*_count
10.2 计算 P95 / P99(非常重要)
histogram_quantile(
0.95,
sum by (le)(
rate(http_request_duration_seconds_bucket[5m])
)
)
10.3 含义拆解
0.95:95 分位le:桶边界rate:速率sum by (le):合并实例
十一、生产环境最佳实践
11.1 性能优化技巧
避免昂贵的查询
# ❌ 避免:在大范围数据上直接聚合
sum(http_requests_total) # 可能很慢
# ✅ 推荐:先采样再聚合
sum(rate(http_requests_total[5m])) # 使用rate缩减数据
# ❌ 避免:过多的标签维度
sum by(pod, container, node, namespace, cluster) (metric)
# ✅ 推荐:精简标签维度
sum by(pod, namespace) (metric)
查询优化模式
# 1. 使用 rate/irate 压缩数据
rate(metric[5m]) # 而不是 metric
# 2. 先过滤后聚合
sum by(job) (rate(metric{instance=~"prod-.*"}[5m])) # 先过滤生产实例
# 3. 避免重复计算
# 错误示例:
rate(a[5m]) + rate(b[5m]) + rate(c[5m])
# 正确示例:
rate(a[5m] + b[5m] + c[5m])
11.2 告警规则设计
告警规则模板
# 节点宕机
- alert: InstanceDown
expr: up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Instance {{ $labels.instance }} down"
description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
# 高内存使用
- alert: HighMemoryUsage
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
for: 10m
labels:
severity: warning
黄金指标监控
# 1. 延迟(Latency)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 2. 流量(Traffic)
rate(http_requests_total[5m])
# 3. 错误(Errors)
rate(http_5xx_errors_total[5m]) / rate(http_requests_total[5m]) * 100
# 4. 饱和度(Saturation)
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100
11.3 调试和故障排查
调试查询
# 1. 使用标量模式调试
scalar(sum(up)) # 返回标量值
# 2. 检查数据是否存在
count(http_requests_total) > 0 # 布尔检查
# 3. 查看标签基数
count by(__name__)({__name__=~".+"}) # 所有指标数量
# 4. 调试标签匹配
{__name__="http_requests_total"} # 查看原始数据
常见问题排查
# 1. 指标不存在
{__name__=~"http.*"} # 模糊匹配
# 2. 数据点稀疏
up{job="my-service"} # 检查抓取间隔
# 3. 标签基数爆炸
count by(job) (count by(__name__, instance) ({__name__=~".+"}))
十二、实战案例集锦
12.1 Kubernetes 集群监控
Pod 资源使用
# Pod CPU 使用率
sum by(namespace, pod) (
rate(container_cpu_usage_seconds_total[2m])
) * 100
# Pod 内存使用率
sum by(namespace, pod) (container_memory_working_set_bytes)
/
sum by(namespace, pod) (kube_pod_container_resource_limits_memory_bytes) * 100
# 重启次数统计
sum by(namespace, pod) (
kube_pod_container_status_restarts_total
) -
sum by(namespace, pod) (
kube_pod_container_status_restarts_total offset 1h
)
节点资源预留
# 节点可分配资源
kube_node_status_allocatable_cpu_cores
kube_node_status_allocatable_memory_bytes
# 已请求资源
sum by(node) (kube_pod_container_resource_requests_cpu_cores)
sum by(node) (kube_pod_container_resource_requests_memory_bytes)
# 资源利用率
(
sum by(node) (kube_pod_container_resource_requests_cpu_cores)
/ kube_node_status_allocatable_cpu_cores * 100
)
12.2 数据库监控
MySQL 监控
# 连接数使用率
mysql_global_status_threads_connected
/
mysql_global_variables_max_connections * 100
# 查询性能
rate(mysql_global_status_questions[5m]) # QPS
rate(mysql_global_status_slow_queries[5m]) # 慢查询
# 缓冲池命中率
(
1 -
mysql_global_status_innodb_buffer_pool_reads
/ mysql_global_status_innodb_buffer_pool_read_requests
) * 100
Redis 监控
# 内存使用
redis_memory_used_bytes / redis_memory_max_bytes * 100
# 命中率
redis_keyspace_hits_total
/
(redis_keyspace_hits_total + redis_keyspace_misses_total) * 100
# 连接数
rate(redis_connected_clients[5m])
12.3 消息队列监控
Kafka 监控
# 主题积压
sum by(topic) (kafka_consumer_group_topic_offset - kafka_topic_partition_current_offset)
# 生产/消费速率
sum by(topic) (rate(kafka_topic_partition_bytes_in[5m]))
sum by(topic) (rate(kafka_topic_partition_bytes_out[5m]))
# 分区状态
kafka_topic_partition_under_replicated_partition # 未同步分区数
十三、性能调优
13.1 查询性能优化
减少数据量
# 1. 使用更短的区间
rate(metric[2m]) # 而不是 [10m]
# 2. 提前过滤
metric{environment="production"} # 而不是在所有数据上过滤
# 3. 减少标签维度
sum by(job) (metric) # 而不是 by(job, instance, pod)
13.2 避免常见陷阱
空值处理
# 避免除零错误
(sum(rate(http_errors_total[5m])) / (sum(rate(http_requests_total[5m])) > 0)) * 100
# 使用 or 运算符处理缺失指标
metric_a or metric_b * 0 # 如果 metric_a 不存在,使用 0
时间窗口选择
# 根据指标特性选择窗口
# 高频变化:短窗口 [1m], [2m]
rate(fast_changing_metric[1m])
# 低频变化:长窗口 [5m], [10m]
rate(slow_changing_metric[10m])
# 告警规则:适当加长窗口避免抖动
avg_over_time(metric[10m]) > threshold
十四、工具和调试技巧
14.1 Prometheus Web UI 使用技巧
Graph 页面高级功能
快捷键:
- Ctrl + Enter: 执行查询
- Ctrl + Space: 自动补全
- Ctrl + /: 注释/取消注释
调试功能:
1. 点击"Execute"查看原始JSON
2. 使用"Graph"和"Console"视图切换
3. 调整时间范围快速验证
常用调试查询
# 1. 查看所有指标名
{__name__=~".+"} # 限制返回数量
{__name__=~"http.*"} # 按前缀过滤
# 2. 查看指标元数据
# 点击指标名旁边的"i"图标
# 3. 测试标签匹配
{job="node"} # 查看所有node job的指标
14.2 promtool 命令行工具
# 1. 检查查询语法
./promtool check promql 'sum(rate(http_requests_total[5m]))'
# 2. 测试查询
./promtool query instant http://localhost:9090 'up'
# 3. 范围查询测试
./promtool query range \
--start=$(date -d '1 hour ago' +%s) \
--end=$(date +%s) \
--step=15s \
http://localhost:9090 \
'rate(http_requests_total[5m])'
总结:一句话掌握 PromQL
PromQL = 对时间序列做"有标签意识的数学运算"

浙公网安备 33010602011771号