强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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]

支持的时间单位:

单位含义示例
s30s
m分钟5m
h小时1h
d7d
w2w
y1y

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)如果无数据返回 1absent(up{job="api"})
absent_over_time(v[d])时间窗口内无数据返回 1absent_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 语法差异

特性PromQLMetricsQL说明
基础语法完全兼容
Subquery✅ (有限)✅ (增强)VM 支持更灵活的嵌套
@ 修饰符VM 支持 end() 函数
多步子查询metric[1h:5m] @ start()
keep_metric_names计算后保留指标名
default设置默认值
if / ifnot条件过滤

5.6.2 函数差异

函数PromQLMetricsQL
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
优化原则精确过滤、缩短窗口、聚合减少序列
子查询支持更灵活的嵌套查询

扩展阅读