Skip to main content

PromQl

Table of Contents

介绍

PromQL 是 prometheus 内置的数据查询语言, 使用 PromQL 对 prometheus 收集的数据进行筛选计算
prometheus 数据格式: data_name{label0=value, label1=value, label2=value} data_value

# Node exporter 收集的 metrics 数据示例

# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 24226.24
node_cpu_seconds_total{cpu="0",mode="iowait"} 0.96
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 0

# HELP node_memory_MemFree_bytes Memory information field MemFree_bytes.
# TYPE node_memory_MemFree_bytes gauge
node_memory_MemFree_bytes 9.904422912e+09

# HELP node_memory_Active_bytes Memory information field Active_bytes.
# TYPE node_memory_Active_bytes gauge
node_memory_Active_bytes 4.65158144e+08

使用 data_name{label0=value, label1=value} 筛选数据

# 显示所有的 node_cpu_seconds_total 数据中 cpu="0" 的数据(不同节点的信息会附带 instance 和 job)
node_cpu_seconds_total{cpu="0"}
> node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", job="Node", mode="idle"} 26274.44
> ......
> node_cpu_seconds_total{cpu="0", instance="10.39.104.158:9100", job="Node", mode="system"} 392.63
> ......
> node_cpu_seconds_total{cpu="0", instance="10.39.104.18:9100", job="Node", mode="steal"} 0

metrics 数据类型

Prometheus 的 metrics 数据有多种类型, 数据注释结尾中会表明数据类型
prometheus 的数据本质是 /proc 下文件内容, /proc 记录着节点, 进程 等的实时数据
ex: /proc/stat (cpu 实时数据) /proc/meminfo (内存实时数据) /proc/<pid> (进程实时数据)

Counter

计数器类型, 数值只增加(除非系统重置), 如 node_cpu_seconds_total 节点 cpu 执行时间

# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 31712.24
node_cpu_seconds_total{cpu="0",mode="iowait"} 0.96
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 0
node_cpu_seconds_total{cpu="0",mode="softirq"} 119.36
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 617.85
node_cpu_seconds_total{cpu="0",mode="user"} 1529.83

Gauge

可增减的仪表盘, 数值可增可减, 用于表示当前状态, node_memory_MemFree_bytes 当前空闲内存

# HELP node_memory_MemFree_bytes Memory information field MemFree_bytes.
# TYPE node_memory_MemFree_bytes gauge
node_memory_MemFree_bytes 9.904422912e+09
# HELP node_memory_MemTotal_bytes Memory information field MemTotal_bytes.
# TYPE node_memory_MemTotal_bytes gauge
node_memory_MemTotal_bytes 2.4360300544e+10
# HELP node_memory_Mlocked_bytes Memory information field Mlocked_bytes.
# TYPE node_memory_Mlocked_bytes gauge
node_memory_Mlocked_bytes 0

Histogram

直方图, 表示一组观测值的分布, 通常用于度量请求持续时间等

# HELP http_request_duration_seconds HTTP request duration in seconds
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 10
http_request_duration_seconds_bucket{le="1"} 20
http_request_duration_seconds_bucket{le="5"} 30
http_request_duration_seconds_bucket{le="10"} 40
http_request_duration_seconds_bucket{le="+Inf"} 50
http_request_duration_seconds_sum 235.5
http_request_duration_seconds_count 50

# 操作次数 50, 耗时 235.5s
# 耗时 小于 0.1s 的有 10次
# 耗时 小于 1s 的有 20次
# 耗时 小于 5s 的有 30次
# 耗时 小于 10s 的有 40次
# 耗时 小于 无穷大的有 50次

Summary

摘要, 类似于 Histogram,但是它会保留一系列指定的分位数

# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216

# 操作的总次数为216次,耗时2.888716127000002s, 按耗时给所有次数排序
# 中位数(quantile=0.5)的耗时为0.012352463
# 9分位数(quantile=0.9)的耗时为0.014458005s

匹配数据

Prometheus 采集的数据有类别, 时间和值类型 3 种属性 使用 PromQL 查询返回的数据有 4 种类型

  • Instan vector: 瞬时向量, 某个时间点采集的数据集合
  • Range vector: 区间向量, 指定时间范围内, 无数瞬时向量的集合
  • Scalar: 标量, 浮点数字, 无时间类别属性
  • String: 字符串

匹配

  • 完全匹配: 等于=, 不等于 !=
  • 正则匹配: 正向 =~ 反向 !~
# cpu0
node_cpu_seconds_total{cpu="0"}

# 非 cpu0
node_cpu_seconds_total{cpu!="0"}

# cpu0 job 中包含 Node
node_cpu_seconds_total{cpu="0",job=~".*Node.*"}

# cpu0 job 中包含 Node
node_cpu_seconds_total{cpu="0",job!~".*Node.*"}

范围查询

上述查询的结果都是瞬时值, 是从最新的数据查询, 这样的结果称为瞬时向量
实际上, prometheus 获取的数据是带有时间的, 一段时间内的数据称作区间向量

# 在瞬时表达式结尾添加 [time] 表示从当前往前一段时间的数据
# 节点 5 分钟前到现在 cpu0 idle 的值(每 15s 查询一次), 34848.9(值) @1708573601.411(时间点)
node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", mode="idle"}[5m]
> node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", mode="idle"} 34848.9 @1708573601.411
> 34863.28 @1708573616.411
> 34877.63 @1708573631.411
> 34892 @1708573646.411
> 34906.3 @1708573661.411
> 34920.6 @1708573676.411
> 34934.85 @1708573691.411
> 34949.08 @1708573706.411
> 34963.29 @1708573721.411
> 34977.53 @1708573736.411
> 34991.82 @1708573751.411
> 35006.06 @1708573766.411
> 35020.08 @1708573781.411
> 35034.16 @1708573796.411
> 35048.44 @1708573811.411
符号smhdwy
含义秒[5s]分钟[5m]小时[5h]天[5d]周[5w]年[5y]

默认查询都是以当前时间作为基准, 取当前时间点或者, 当前往前推一段时间
若要更换时间基准, 如 1 天前同一时刻, 或者昨天一整天的数据, 使用 offset 切换时间基准

# 当前时间往前推 1 天
node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", mode="idle"} offset 1d

# 当前是 02/22 10:00, 先往前推 10 小时到 00:00, 再取 00:00 往前 1 天的数据
node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", mode="idle"}[1d] offset 10h

聚合操作

对瞬时向量进行聚合操作

  • sum: 求和 sum(node_cpu_seconds_total{cpu="0"})
  • min: 最小值 min(node_cpu_seconds_total{cpu="0"})
  • max: 最大值 max(node_cpu_seconds_total{cpu="0"})
  • avg: 平均值 avg(node_cpu_seconds_total{cpu="0"})
  • count: 计数 count(node_cpu_seconds_total{cpu="0"})
  • topk: 前 n 条数据 topk(5, node_cpu_seconds_total{cpu="0"})
  • bottomk: 最后 n 条数据 bottomkk(5, node_cpu_seconds_total{cpu="0"})
  • stddev: 标准差

数学运算

瞬时向量可以直接与标量计算, 如 Memory 原始数据单位是 Byte, 除以 1024, 单位变成 KB 瞬时向量和瞬时向量运算, 只有 {label0=value, label1=value} 完全一致才会计算
使用 onignore 让不同标签的向量也能做数学运算

node_cpu_seconds_total  +  on(instance, job, mode, cpu) node_cpu_guest_seconds_total

内置函数

increase

计算一个 Counter 数据的增长, 取最后时刻的数据减去最初时刻的数据
increase(range-vector)

increase(node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", job="V2-Node",mode="idle"}[5m])
> {cpu="0", instance="10.143.232.175:9100", job="V2-Node", mode="idle"} 218.2709700476184

rate

计算平均每秒的增长, 即增长量除以时间 rate(range-vector) == increase(range-vector) / time

rate(node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", job="V2-Node",mode="idle"}[5m])
> {cpu="0", instance="10.143.232.175:9100", job="V2-Node", mode="idle"} 0.7518475626666798

irate

计算最后两组数据的增长率(瞬时变化): 最后的数据 - 最后前一次数据 / 两个数据时间差

# 由于仅取最后两组数据, 在同一个时间点, [2m] [5m] (无论往前推多少时间)的最后两组数据一致, 结果也一致
irate(node_cpu_seconds_total{cpu="0", instance="10.143.232.175:9100", job="V2-Node",mode="idle"}[2m])
> {cpu="0", instance="10.143.232.175:9100", job="V2-Node", mode="idle"} 0.8286666666666861

示例

节点连接

# job 中包含 Node 的(1 连接, 0 断连)
up{job=~".*Node"}
up{instance="10.121.238.42:6100", job="V2-Node"} 1
up{instance="10.121.238.42:7100", job="V2-Node"} 1
up{instance="10.143.232.175:9100", job="V2-Node"} 1
up{instance="10.144.226.244:9100", job="V1-Node"} 1

CPU 占用率

/proc/stat 保存 CPU 执行时间数据(Counter类型)
CPU 占用: 一段时间内, CPU 工作时间(总时间 - 空闲时间)占总时间的比值

字段usernicesystemidleiowaitirqsoftirqsteal/guest/guest_nice
11281550990765528013498147055470/0/0
含义用户态时间低优先级用户态时间内核态时间空闲时间I/O等待时间硬中断时间软中断时间虚拟机占用时间

CPU Used = 1 - (idle / (user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice))

# 2m 最后两组数据计算平均增长率
irate(node_cpu_seconds_total{mode="idle"}[2m])
irate(node_cpu_seconds_total[2m])

# 1 减去空闲百分比获得 CPU 占用百分比(按)
1 - (sum by(instance) (irate(node_cpu_seconds_total{mode="idle"}[2m])) / sum by(instance) (irate(node_cpu_seconds_total[2m])))
1 - ((irate(node_cpu_seconds_total{mode="idle", instance="192.168.1.100"}[2m])) / (irate(node_cpu_seconds_total{instance="192.168.1.100"}[2m])))
# 注: sum by 语句后仅保留设置的索引, 类似于 pandas 的 groupby
sum by(job,instance) (node_cpu_seconds_total{mode="idle"})
{instance="10.121.238.42:1100", job="V2-Node"} 192876.24
{instance="10.121.238.42:2100", job="V2-Node"} 1113100.96
{instance="10.121.238.42:6100", job="V2-Node"} 1156084.41
{instance="10.121.238.42:7100", job="V2-Node"} 1154130.68

内存占用

/proc/meminfo 保存 Memory 数据(Gauge类型)
Memory Used: (MemTotal - MemAvailable) / MemTotal

# 已使用内存(单位 Byte)
node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes

# 已使用内存(单位 GB)
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 1024 / 1024 / 1024

# 内存占用百分比
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes

硬盘占用

Disk Used: 1- (Disk Available / Disk Total)

# 可用空间
node_filesystem_avail_bytes

# 硬盘总空间
node_filesystem_size_bytes

1 - ((node_filesystem_avail_bytes) / node_filesystem_size_bytes)

API

prometheus 提供了API, 可以通过 API 获取数据

import requests

# 查询瞬时数据
query_url = "http://localhost:9090/api/v1/query"
r = requests.get(query_url, params={"query": 'node_cpu_seconds_total{mode="idle", "instance": "192.168.1.100:9100", "cpu"="0"}'})
r.json()

{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "node_cpu_seconds_total",
"cpu": "0",
"instance": "192.168.1.100:9100",
"job": "Node",
"mode": "idle"
},
"value": [1719297314.563, "26458.92"]
}
]
}
}

# 查询时间段数据
query_range_url = "http://localhost:9090/api/v1/query_range"
r = requests.get(query_range_url, params={
"query": 'node_cpu_seconds_total{mode="idle", "instance": "192.168.1.100:9100", "cpu"="0"}',
"start": "2024-06-25T12:00:00+08:00",
"end": "2024-06-25T12:05:00+08:00",
"step": "1m"
})
r.json()

{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "node_cpu_seconds_total",
"cpu": "0",
"instance": "192.168.1.100:9100",
"job": "Node",
"mode": "idle"
},
"values": [
[1719230400, "4454.3"],
[1719230460, "4504.85"],
[1719230520, "4555.09"],
[1719230580, "4605.51"],
[1719230640, "4655.95"],
[1719230700, "4697.64"]
]
}
]
}
}