VictoriaMetrics 完全指南 / 05 - MetricsQL 查询语言
05 · MetricsQL 查询语言
本章目标
- 掌握 MetricsQL 的完整语法体系
- 熟悉常用内置函数及其业务场景
- 理解 MetricsQL 与 PromQL 的差异
- 学会编写高效的查询表达式
- 掌握调试和优化查询的技巧
5.1 MetricsQL 概述
MetricsQL 是 VictoriaMetrics 自研的查询语言,完全兼容 PromQL,并在此基础上新增了大量实用函数和语法增强。
兼容性说明
PromQL 语法 ──────────────────── 100% 兼容 ✅
│
▼ 扩展
MetricsQL 新增函数 ──────────── 50+ 个新函数
MetricsQL 语法增强 ──────────── 更灵活的表达式
5.2 基础语法
5.2.1 即时向量(Instant Vector)
选择当前时间点的所有时间序列:
# 选择所有 cpu_usage 系列
cpu_usage
# 带标签过滤
cpu_usage{host="web01"}
# 正则匹配
cpu_usage{host=~"web0[1-3]"}
# 排除匹配
cpu_usage{host!~"test.*"}
# 多条件(AND 逻辑,隐式)
cpu_usage{host="web01", region="cn-north"}
5.2.2 范围向量(Range Vector)
选择一段时间范围内的数据点:
# 最近 5 分钟的数据
cpu_usage[5m]
# 最近 1 小时
http_requests_total[1h]
# 最近 30 秒
node_network_receive_bytes_total[30s]
支持的时间单位:
| 单位 | 含义 | 示例 |
|---|
s | 秒 | 30s |
m | 分钟 | 5m |
h | 小时 | 1h |
d | 天 | 7d |
w | 周 | 2w |
y | 年 | 1y |
5.2.3 偏移修饰符(Offset)
# 查看 1 小时前的值
cpu_usage offset 1h
# 查看 1 天前的值
cpu_usage offset 1d
# 对比当前与 1 天前
cpu_usage - (cpu_usage offset 1d)
5.2.4 @ 修饰符(指定时间点)
# 查询 2024-01-15T10:00:00Z 时刻的值
cpu_usage @ 1705312800
# 查询 1 小时前的值(等价于 offset 1h)
cpu_usage @ (end() - 3600)
5.3 聚合操作
5.3.1 基础聚合函数
| 函数 | 说明 | 示例 |
|---|
sum | 求和 | sum(http_requests_total) |
avg | 平均值 | avg(cpu_usage) |
min | 最小值 | min(cpu_usage) |
max | 最大值 | max(cpu_usage) |
count | 计数 | count(cpu_usage) |
stddev | 标准差 | stddev(cpu_usage) |
stdvar | 方差 | stdvar(cpu_usage) |
topk | 前 K 个 | topk(5, cpu_usage) |
bottomk | 后 K 个 | bottomk(5, cpu_usage) |
quantile | 分位数 | quantile(0.99, cpu_usage) |
5.3.2 分组聚合(by / without)
# 按 region 分组求平均
avg by (region) (cpu_usage)
# 按 region 和 env 分组求和
sum by (region, env) (http_requests_total)
# 排除 host 标签求平均(按剩余标签分组)
avg without (host) (cpu_usage)
# 按所有标签分组(等价于不去除任何标签)
sum by () (up)
# 不分组(全局聚合)
sum without () (cpu_usage)
5.3.3 聚合操作流程图
输入:cpu_usage{host="web01", region="cn-north"} = 72.5
cpu_usage{host="web02", region="cn-north"} = 45.3
cpu_usage{host="db01", region="cn-south"} = 32.7
avg(cpu_usage) → (72.5 + 45.3 + 32.7) / 3 = 50.17
avg by (region) (cpu_usage):
→ {region="cn-north"} = (72.5 + 45.3) / 2 = 58.9
→ {region="cn-south"} = 32.7
sum by (host) (cpu_usage):
→ {host="web01"} = 72.5
→ {host="web02"} = 45.3
→ {host="db01"} = 32.7
5.4 常用函数
5.4.1 计数器函数
| 函数 | 说明 | 适用场景 |
|---|
rate(v[d]) | 每秒增长率(简单平均) | 计数器的速率计算 |
irate(v[d]) | 瞬时增长率(最后两个点) | 高灵敏度速率图表 |
increase(v[d]) | 指定时间窗口的增长量 | 统计一段时间的请求量 |
resets(v[d]) | 计数器重置次数 | 检测异常重启 |
# 计算每秒请求数
rate(http_requests_total[5m])
# 计算每分钟请求数
rate(http_requests_total[5m]) * 60
# 计算 5 分钟内的总请求量
increase(http_requests_total[5m])
# 瞬时速率(适合高精度图表)
irate(http_requests_total[5m])
# 检测过去 1 小时内有多少次重启
resets(process_resident_memory_bytes[1h])
5.4.2 Gauge 函数
| 函数 | 说明 | 示例 |
|---|
avg_over_time(v[d]) | 时间窗口内平均值 | avg_over_time(cpu_usage[1h]) |
min_over_time(v[d]) | 时间窗口内最小值 | min_over_time(cpu_usage[1h]) |
max_over_time(v[d]) | 时间窗口内最大值 | max_over_time(cpu_usage[1h]) |
sum_over_time(v[d]) | 时间窗口内求和 | sum_over_time(requests[1h]) |
count_over_time(v[d]) | 时间窗口内计数 | count_over_time(up[1h]) |
last_over_time(v[d]) | 时间窗口内最后一个值 | last_over_time(cpu_usage[5m]) |
quantile_over_time(q, v[d]) | 时间窗口内分位数 | quantile_over_time(0.99, latency[1h]) |
stddev_over_time(v[d]) | 时间窗口内标准差 | stddev_over_time(cpu_usage[1h]) |
changes(v[d]) | 值变化的次数 | changes(up[1h]) |
delta(v[d]) | 首尾值的差 | delta(temperature[1h]) |
deriv(v[d]) | 每秒导数(线性回归) | deriv(temperature[1h]) |
predict_linear(v[d], t) | 线性预测 | predict_linear(disk_free[1h], 3600*24) |
# 过去 1 小时的平均 CPU 使用率
avg_over_time(cpu_usage[1h])
# 过去 24 小时的 P99 延迟
quantile_over_time(0.99, http_request_duration_seconds[24h])
# 预测 24 小时后的磁盘使用率
predict_linear(disk_usage[7d], 3600*24)
# 过去 1 小时内值变化了多少次
changes(up[1h])
5.4.3 数学函数
| 函数 | 说明 |
|---|
abs(v) | 绝对值 |
ceil(v) | 向上取整 |
floor(v) | 向下取整 |
round(v, nearest) | 四舍五入到最近的倍数 |
clamp(v, min, max) | 限制在 [min, max] 范围 |
clamp_min(v, min) | 限制最小值 |
clamp_max(v, max) | 限制最大值 |
exp(v) | 指数函数 |
ln(v) | 自然对数 |
log2(v) | 以 2 为底的对数 |
log10(v) | 以 10 为底的对数 |
sqrt(v) | 平方根 |
# 将 CPU 使用率四舍五入到整数
round(cpu_usage)
# 限制在 0-100 范围
clamp(cpu_usage, 0, 100)
# 向上取整
ceil(http_request_duration_seconds)
5.4.4 标签操作函数
| 函数 | 说明 | 示例 |
|---|
label_replace(v, dst, src, regex, repl) | 正则替换/提取标签 | label_replace(up, "host", "$1", "instance", "(.*):.*") |
label_join(v, dst, sep, src1, src2, ...) | 合并标签值 | label_join(up, "addr", ":", "host", "port") |
sort(v) | 按值升序排序 | sort(cpu_usage) |
sort_desc(v) | 按值降序排序 | sort_desc(cpu_usage) |
absent(v) | 如果无数据返回 1 | absent(up{job="api"}) |
absent_over_time(v[d]) | 时间窗口内无数据返回 1 | absent_over_time(up[5m]) |
# 从 instance 标签提取 host
label_replace(
up,
"host", # 目标标签
"$1", # 替换模板
"instance", # 源标签
"(.*):.*" # 正则表达式
)
# 合并 host 和 port 标签
label_join(up, "endpoint", ":", "host", "port")
# 排序 - 查看 CPU 最高的 5 台主机
topk(5, sort_desc(cpu_usage))
5.4.5 向量匹配
一对一匹配:
# 默认按完全相同的标签匹配
cpu_usage - memory_usage
# on() 指定匹配的标签
cpu_usage{host="web01"} - on(host) memory_usage{host="web01"}
# ignoring() 指定忽略的标签
cpu_usage - ignoring(region) memory_usage
多对一 / 一对多匹配:
# group_left:右侧多个系列对应左侧一个系列
http_requests_total
* on(host) group_left(region)
server_info
# group_left:左侧多个系列对应右侧一个系列
http_errors
/ on(host) group_left()
http_requests_total
多对一匹配示意:
http_requests_total{host="web01"} = 1000
http_requests_total{host="web02"} = 2000
× on(host) group_left(region)
server_info{host="web01", region="cn"} = (region标签来自server_info)
server_info{host="web02", region="cn"} = (region标签来自server_info)
结果:
{host="web01", region="cn"} = 1000 × 1
{host="web02", region="cn"} = 2000 × 1
5.5 MetricsQL 独有函数
以下是 VictoriaMetrics 在 PromQL 基础上新增的函数:
5.5.1 rollup 系列
# rollup - 通用滚动窗口函数
rollup(cpu_usage) # 等价于默认聚合
# default_rollup - 对 Gauge 类型使用 last,Counter 使用 rate
default_rollup(cpu_usage)
# rollup_rate - 类似 rate 但更精确
rollup_rate(http_requests_total)
# rollup_increase - 类似 increase 但更精确
rollup_increase(http_requests_total)
5.5.2 数组与集合
# union - 合并多个不同指标到一个结果集
union(
{__name__="cpu_usage", host="web01"},
{__name__="memory_usage", host="web01"}
)
# keep_metric_names - 在计算后保留原始 metric name
(cpu_usage + 0) keep_metric_names
# label_set - 手动设置标签
label_set(cpu_usage, "team", "platform")
# label_del - 删除标签
label_del(cpu_usage, "host")
# label_copy - 复制标签
label_copy(cpu_usage, "host", "instance")
# label_move - 重命名标签
label_move(cpu_usage, "host", "hostname")
# label_map - 标签值映射
label_map(env, "prod", "production", "dev", "development")
# label_transform - 正则替换标签值
label_transform(host, "\\..*", "") # 去掉域名后缀
5.5.3 统计函数
# histogram_quantile - 直方图分位数(PromQL 也有,VM 增强版)
histogram_quantile(0.99, sum by(le) (rate(http_duration_bucket[5m])))
# count_values - 按值分组计数
count_values("version", up)
# stddev_over_time - 时间窗口标准差
stddev_over_time(cpu_usage[1h])
# range_over_time - 时间窗口内的值范围(max - min)
range_over_time(cpu_usage[1h])
# tmin_over_time - 时间窗口内最小值对应的时间点
tmin_over_time(temperature[1h])
# tmax_over_time - 时间窗口内最大值对应的时间点
tmax_over_time(temperature[1h])
5.5.4 条件与过滤
# if - 条件筛选
cpu_usage if cpu_usage > 80 # 只保留 > 80 的序列
cpu_usage if memory_usage > 70 # 基于另一个指标的条件
# ifnot - 反条件筛选
cpu_usage ifnot cpu_usage < 50 # 排除 < 50 的序列
# default - 设置默认值
(http_errors / http_total) default 0
5.6 与 PromQL 完整对比
5.6.1 语法差异
| 特性 | PromQL | MetricsQL | 说明 |
|---|
| 基础语法 | ✅ | ✅ | 完全兼容 |
| Subquery | ✅ (有限) | ✅ (增强) | VM 支持更灵活的嵌套 |
@ 修饰符 | ✅ | ✅ | VM 支持 end() 函数 |
| 多步子查询 | ❌ | ✅ | metric[1h:5m] @ start() |
keep_metric_names | ❌ | ✅ | 计算后保留指标名 |
default | ❌ | ✅ | 设置默认值 |
if / ifnot | ❌ | ✅ | 条件过滤 |
5.6.2 函数差异
| 函数 | PromQL | MetricsQL |
|---|
rollup | ❌ | ✅ |
default_rollup | ❌ | ✅ |
rollup_rate | ❌ | ✅ |
range_over_time | ❌ | ✅ |
tmin_over_time | ❌ | ✅ |
tmax_over_time | ❌ | ✅ |
label_map | ❌ | ✅ |
label_transform | ❌ | ✅ |
union | ❌ | ✅ |
histogram_quantile | ✅ | ✅ (增强) |
rate / increase | ✅ | ✅ (增强) |
5.6.3 行为差异
# PromQL:rate 在 counter 重置时可能返回 NaN
# MetricsQL:自动处理 counter 重置,返回正确值
# PromQL:staleness 检测默认 5 分钟
# MetricsQL:可自定义 -search.maxStalenessInterval
# PromQL:label_replace 不保留空标签
# MetricsQL:label_replace 可以创建空标签
5.7 查询优化
5.7.1 性能优化原则
| 原则 | 说明 | 示例 |
|---|
| 精确标签过滤 | 减少扫描的序列数 | cpu_usage{host="web01"} > cpu_usage |
| 缩短时间窗口 | 减少数据点数 | rate(x[1m]) > rate(x[1h]) |
使用 by 聚合 | 减少返回序列数 | avg by (host)(x) > avg(x) |
| 避免正则 | 正则匹配慢于精确匹配 | host="web01" > host=~"web.*" |
使用 default_rollup | 更精确的计算 | default_rollup(x) |
5.7.2 常见查询优化案例
# ❌ 不推荐:全量扫描
cpu_usage
# ✅ 推荐:精确过滤
cpu_usage{env="prod"}
# ❌ 不推荐:大时间窗口 rate
rate(http_requests_total[1h])
# ✅ 推荐:小时间窗口
rate(http_requests_total[5m])
# ❌ 不推荐:嵌套聚合
sum(avg(cpu_usage))
# ✅ 推荐:一次聚合
avg(cpu_usage)
# ❌ 不推荐:返回过多序列
cpu_usage{env="prod"}
# ✅ 推荐:聚合后返回
avg by (host) (cpu_usage{env="prod"})
5.8 业务场景查询示例
场景一:服务可用性监控
# 服务可用率
100 * (
sum by (job) (up{job="api-server"}) /
count by (job) (up{job="api-server"})
)
# 检测服务是否存活(告警用)
absent(up{job="api-server"} == 1)
# 过去 5 分钟内的可用率
100 * avg_over_time(up{job="api-server"}[5m])
场景二:请求延迟分析
# P50 延迟
histogram_quantile(0.50, sum by(le) (rate(http_duration_bucket[5m])))
# P99 延迟
histogram_quantile(0.99, sum by(le) (rate(http_duration_bucket[5m])))
# 按服务分组的 P99 延迟
histogram_quantile(0.99,
sum by (le, job) (rate(http_duration_bucket[5m]))
)
# 延迟突增检测(当前 vs 1小时前)
(
histogram_quantile(0.99, sum by(le) (rate(http_duration_bucket[5m]))) /
histogram_quantile(0.99, sum by(le) (rate(http_duration_bucket[5m] offset 1h)))
) > 1.5 # 延迟增长超过 50%
场景三:容量规划
# 预测未来 7 天的磁盘使用
predict_linear(disk_free[7d], 3600*24*7) < 0
# 过去 30 天的 CPU 使用率 P95
quantile_over_time(0.95, cpu_usage[30d])
# 内存使用趋势(每天同一时间的对比)
avg by (day) (
label_transform(
avg_over_time(memory_usage[1d]),
"day", ".*", "avg"
)
)
场景四:错误率监控
# HTTP 错误率
100 * sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m]))
# 只在错误率 > 1% 时显示
100 * sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/ sum by (job) (rate(http_requests_total[5m])) > 1
# 按状态码分组的错误分布
sum by (status) (rate(http_requests_total{status=~"[45].."}[5m]))
本章小结
| 要点 | 内容 |
|---|
| 兼容性 | MetricsQL 完全兼容 PromQL |
| 新增函数 | rollup、default_rollup、label_map 等 50+ 个 |
| 语法增强 | if / ifnot、default、keep_metric_names |
| 优化原则 | 精确过滤、缩短窗口、聚合减少序列 |
| 子查询 | 支持更灵活的嵌套查询 |
扩展阅读