05 - PromQL 基础
05 - PromQL 基础
5.1 PromQL 概述
PromQL(Prometheus Query Language)是 Prometheus 内置的查询语言,用于查询和聚合时间序列数据。它功能强大,支持即时查询、范围查询、聚合运算、多维过滤等操作。
查询类型
| 类型 | API 端点 | 说明 |
|---|
| 即时查询(Instant Query) | /api/v1/query | 返回当前时刻的值 |
| 范围查询(Range Query) | /api/v1/query_range | 返回一段时间内的值 |
# 即时查询
curl 'http://localhost:9090/api/v1/query?query=up'
# 范围查询
curl 'http://localhost:9090/api/v1/query_range?query=up&start=2024-01-01T00:00:00Z&end=2024-01-01T01:00:00Z&step=15s'
5.2 时间序列数据模型
数据类型
PromQL 中有四种数据类型(表达式类型):
| 类型 | 说明 | 示例 |
|---|
| 即时向量(Instant Vector) | 每个时间序列一个数据点 | http_requests_total |
| 范围向量(Range Vector) | 每个时间序列多个数据点 | http_requests_total[5m] |
| 标量(Scalar) | 单个浮点数 | 1 + 1 |
| 字符串(String) | 单个字符串 | "hello" |
即时向量 vs 范围向量
即时向量: 每个序列返回 1 个数据点(当前时刻)
┌────────────────────┐
│ series1: value@T │
│ series2: value@T │
│ series3: value@T │
└────────────────────┘
范围向量: 每个序列返回 N 个数据点(时间范围)
┌────────────────────────────────────────────┐
│ series1: [value@T-4m, value@T-3m, ..., @T] │
│ series2: [value@T-4m, value@T-3m, ..., @T] │
│ series3: [value@T-4m, value@T-3m, ..., @T] │
└────────────────────────────────────────────┘
5.3 选择器(Selectors)
选择器用于过滤和匹配时间序列。
标签匹配器
| 匹配器 | 符号 | 说明 | 示例 |
|---|
| 等于 | = | 精确匹配 | job="api" |
| 不等于 | != | 排除匹配 | job!="api" |
| 正则匹配 | =~ | 正则表达式匹配 | status=~"2.." |
| 正则排除 | !~ | 正则表达式排除 | status!~"2.." |
基础选择器
# 1. 精确匹配指标名称
http_requests_total
# 2. 精确匹配标签
http_requests_total{job="api-server"}
# 3. 多标签匹配(AND 逻辑)
http_requests_total{job="api-server", method="GET"}
# 4. 不等于
http_requests_total{status!="200"}
# 5. 正则匹配
http_requests_total{status=~"2.."}
# 6. 正则排除
http_requests_total{status!~"2.."}
# 7. 复杂正则
http_requests_total{path=~"/api/(users|orders).*", method=~"GET|POST"}
指标名称正则匹配
# 匹配多个指标名称
{__name__=~"http_requests.*"}
# 匹配所有 http 开头的 Counter
{__name__=~"http_.*_total"}
# 匹配特定 job 的所有指标
{job="api-server"}
范围向量选择器
# 过去 5 分钟的数据
http_requests_total[5m]
# 过去 1 小时的数据
http_requests_total[1h]
# 使用不同的时间单位
http_requests_total[30s] # 秒
http_requests_total[5m] # 分钟
http_requests_total[2h] # 小时
http_requests_total[7d] # 天
http_requests_total[1w] # 周
http_requests_total[1y] # 年
Offset 修饰符
# 当前时刻的值
http_requests_total
# 1 小时前的值
http_requests_total offset 1h
# 1 天前的值
http_requests_total offset 1d
# 计算过去 1 小时的增长率 vs 前 1 小时的增长率
rate(http_requests_total[5m])
/
rate(http_requests_total[5m] offset 1h)
# 一周同期对比
http_requests_total offset 1w
@ 修饰符
# 查询特定时间点的值
http_requests_total @ 1609459200
# 配合 offset
http_requests_total @ 1609459200 offset 1h
# 查询当前时间(start() 和 end() 用于范围查询)
http_requests_total @ start()
http_requests_total @ end()
5.4 运算符(Operators)
算术运算符
| 运算符 | 说明 | 示例 |
|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取模 | a % b |
^ | 幂运算 | a ^ 2 |
# 内存使用率(百分比)
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
# 磁盘使用率
(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100
# 单位转换:字节转 GB
node_memory_MemTotal_bytes / 1024 / 1024 / 1024
# 请求错误率(百分比)
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100
比较运算符
| 运算符 | 说明 | 示例 |
|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
# 过滤出使用率超过 90% 的文件系统
(node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1
# 使用 bool 修饰符返回 0 或 1
(node_filesystem_avail_bytes / node_filesystem_size_bytes) < bool 0.1
逻辑运算符(集合运算符)
| 运算符 | 说明 | 说明 |
|---|
and | 交集 | 两边都存在的序列 |
or | 并集 | 任一边存在的序列 |
unless | 差集 | 左边存在但右边不存在的序列 |
# 获取同时有 HTTP 和 gRPC 指标的实例
http_requests_total and grpc_requests_total
# 获取有 HTTP 指标或 gRPC 指标的实例
http_requests_total or grpc_requests_total
# 获取有 HTTP 指标但没有 gRPC 指标的实例
http_requests_total unless grpc_requests_total
向量匹配
当两个向量进行运算时,需要匹配对应的标签。
一对一匹配(One-to-one):
# 默认按所有标签匹配
http_requests_success / http_requests_total
# 使用 on() 指定匹配标签
http_requests_success / on(instance, job) http_requests_total
# 使用 ignoring() 排除某些标签
http_requests_success / ignoring(status) http_requests_total
多对一/一对多匹配:
# group_left: 左边有多条序列,右边只有一条
http_requests_total * on(instance) group_left(node_name) node_info
# group_right: 右边有多条序列,左边只有一条
node_info * on(instance) group_right() http_requests_total
5.5 聚合函数
PromQL 提供了丰富的聚合函数,用于对多个时间序列进行聚合。
聚合函数列表
| 函数 | 说明 |
|---|
sum() | 求和 |
min() | 最小值 |
max() | 最大值 |
avg() | 平均值 |
count() | 计数 |
stddev() | 标准差 |
stdvar() | 方差 |
topk(k, v) | 前 k 个最大值 |
bottomk(k, v) | 前 k 个最小值 |
quantile(q, v) | 分位数 |
count_values("label", v) | 按值计数 |
group(v) | 返回值为 1 的序列 |
使用 by 和 without
# by: 按指定标签分组聚合
sum by (job) (rate(http_requests_total[5m]))
# without: 排除指定标签,按其余标签分组
sum without(instance) (rate(http_requests_total[5m]))
# 每个 job 的请求速率
sum by (job) (rate(http_requests_total[5m]))
# 每个 instance 的总 CPU 使用率
avg by (instance) (rate(node_cpu_seconds_total{mode!="idle"}[5m]))
# 每个 job 的 P99 延迟
histogram_quantile(0.99, sum by (job, le) (rate(http_request_duration_seconds_bucket[5m])))
实用聚合示例
# 1. 每个服务的请求速率 (QPS)
sum by (job) (rate(http_requests_total[5m]))
# 2. 错误率(按状态码分类)
sum by (status) (rate(http_requests_total[5m]))
# 3. 每台机器的内存使用率
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# 4. CPU 使用率(排除 idle)
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 5. 磁盘使用率(根分区)
(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100
# 6. 网络流量速率(MB/s)
rate(node_network_receive_bytes_total[5m]) / 1024 / 1024
# 7. Top 5 CPU 使用率最高的实例
topk(5, 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100))
# 8. 统计各状态码的数量
count_values("status_code", http_requests_total)
5.6 内置函数
速率函数
| 函数 | 适用类型 | 说明 |
|---|
rate(v) | Counter | 每秒平均速率(基于范围向量) |
increase(v) | Counter | 范围内的增量 |
irate(v) | Counter | 瞬时速率(基于最后两个点) |
irate(v) | Counter | 瞬时速率(更敏感,适合图表) |
# rate: 平滑的每秒速率(推荐用于告警和录制规则)
rate(http_requests_total[5m])
# increase: 过去 1 小时的增量
increase(http_requests_total[1h])
# irate: 瞬时速率(更敏感,适合实时图表)
irate(http_requests_total[5m])
rate vs irate 区别:
───────────────────
rate: 使用范围内所有点计算平均斜率
─────── ─────── ─────── ───────
点1 点2 点3 点4
↓ ↓
计算所有点的平均斜率 → 平滑曲线
irate: 只使用最后两个点计算斜率
─────── ─────── ─────── ───────
点1 点2 点3 点4
↓↓
只看最后两点 → 敏感波动
最佳实践:告警规则用 rate()(平滑),实时图表用 irate()(灵敏)。时间窗口建议为采集间隔的 4 倍(如 15s 间隔用 1m)。
时间函数
| 函数 | 说明 | 示例 |
|---|
time() | 当前 Unix 时间戳 | time() |
timestamp(v) | 返回序列的时间戳 | timestamp(up) |
day_of_week() | 星期几(0=Sunday) | day_of_week() |
day_of_month() | 每月第几天 | day_of_month() |
hour() | 小时(0-23) | hour() |
数学函数
| 函数 | 说明 |
|---|
abs(v) | 绝对值 |
ceil(v) | 向上取整 |
floor(v) | 向下取整 |
round(v, to_nearest) | 四舍五入 |
clamp(v, min, max) | 限制在范围 |
clamp_min(v, min) | 最小值限制 |
clamp_max(v, max) | 最大值限制 |
sort(v) | 升序排列 |
sort_desc(v) | 降序排列 |
字符串函数
| 函数 | 说明 |
|---|
label_replace(v, dst, src, regex, replacement) | 标签替换 |
label_join(v, dst, separator, src1, src2, ...) | 标签合并 |
# 从 instance 标签提取主机名
label_replace(up, "hostname", "$1", "instance", "(.*):.*")
# 合并标签
label_join(up, "host_port", ":", "instance", "port")
5.7 经典查询示例
RED 方法(微服务监控)
# Rate: 每秒请求数
sum by (job) (rate(http_requests_total[5m]))
# Error: 错误率
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total[5m]))
# Duration: P99 延迟
histogram_quantile(0.99,
sum by (job, le) (rate(http_request_duration_seconds_bucket[5m]))
)
USE 方法(基础设施监控)
# Utilization: CPU 使用率
100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100
# Saturation: 系统负载 (1分钟)
node_load1
# Saturation: 内存使用率
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# Error: 磁盘 IO 错误
rate(node_disk_io_errors_total[5m])
告警条件示例
# 实例宕机
up == 0
# CPU 使用率超过 80%
(100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
# 磁盘空间不足(剩余 < 10%)
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
# 内存使用率超过 90%
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9
# 请求错误率超过 5%
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m])) > 0.05
5.8 本章小结
| 概念 | 说明 |
|---|
| 选择器 | {label="value"}, =~, !~ |
| 即时向量 | 当前时刻的数据点集合 |
| 范围向量 | 时间范围内的数据点集合 |
| 运算符 | 算术、比较、逻辑、向量匹配 |
| 聚合 | sum, avg, max, topk + by/without |
| 核心函数 | rate(), increase(), histogram_quantile() |
扩展阅读
上一章:04 - 指标类型
下一章:06 - PromQL 进阶