Prometheus 核心概念
本文档涵盖 Prometheus 四种核心指标类型和 PromQL 查询语言。选择合适的指标类型和掌握 PromQL 对查询性能、存储效率和告警准确性至关重要。
符号说明
| 符号 | 含义 |
|---|---|
| 🚨 | 陷阱 / Pitfall |
| 💡 | 最佳实践 / Best practice |
| 🔬 | 深入原理 / Deep-dive |
| ⚡ | 性能提示 / Performance note |
1. 指标类型详解
Prometheus 提供四种核心指标类型。
1.1 Counter(计数器)
特点: 只增不减(除非进程重启导致重置为 0)。
适用场景: 请求总数、错误次数、完成任务数、累计字节数。
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET", status="200"} 1048576
http_requests_total{method="POST", status="201"} 524288| 关键操作 | 说明 |
|---|---|
Inc() / Add(n) |
增加计数 |
⛔ 不可 Dec() |
Counter 不可减少 |
🔬 深入原理: Counter 存储的是累计值,直接使用这个值没有意义。必须用 rate() 或 increase() 转换成每秒速率或时间窗口内增量。rate() 能自动处理计数器重置(比如进程重启时归零)。
1.2 Gauge(仪表盘)
特点: 可增可减,反映当前瞬时状态。
适用场景: CPU 使用率、内存占用、活跃连接数、队列深度、温度。
# HELP node_memory_MemAvailable_bytes Available memory
# TYPE node_memory_MemAvailable_bytes gauge
node_memory_MemAvailable_bytes 8589934592| 关键操作 | 说明 |
|---|---|
Set(v) |
设为指定值 |
Inc() / Dec() |
+1 / -1 |
Add(n) / Sub(n) |
批量加减 |
💡 Gauge 可直接查询当前值,不需要套 rate()。但对 Gauge 做趋势分析时,用 delta()、deriv()、predict_linear()。
1.3 Histogram(直方图)
特点: 将观测值落入预定义的桶(bucket)中计数,自动生成 _bucket、_sum、_count 三个子指标。
适用场景: 请求延迟分布、响应体大小分布——任何需要跨实例聚合后计算分位数的场景。
# HELP http_request_duration_seconds HTTP request duration
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.005"} 0
http_request_duration_seconds_bucket{le="0.01"} 15
http_request_duration_seconds_bucket{le="0.025"} 55
http_request_duration_seconds_bucket{le="0.05"} 143
http_request_duration_seconds_bucket{le="0.1"} 321
http_request_duration_seconds_bucket{le="0.25"} 567
http_request_duration_seconds_bucket{le="0.5"} 712
http_request_duration_seconds_bucket{le="1.0"} 843
http_request_duration_seconds_bucket{le="+Inf"} 1000
http_request_duration_seconds_sum 245.6
http_request_duration_seconds_count 1000🔬 深入原理: Histogram 的核心价值在于 可聚合。多个实例的 _bucket 可以用 sum() 合并,再用 histogram_quantile() 算出全局分位数。这是 Summary 做不到的。
💡 桶的边界应对齐 SLO 阈值。 比如 SLO 是 P99 < 500ms,就该在 100ms、250ms、500ms、1s 处设桶。
1.4 Summary(摘要)
特点: 在客户端直接计算分位数(φ-quantile),暴露 _sum、_count 和带 quantile 标签的分位数值。
适用场景: 单实例的精确分位数(不需要跨实例聚合时)。
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.23e-05
go_gc_duration_seconds{quantile="0.5"} 0.000123
go_gc_duration_seconds{quantile="0.9"} 0.000456
go_gc_duration_seconds{quantile="0.99"} 0.001234
go_gc_duration_seconds_sum 52.3
go_gc_duration_seconds_count 100001.5 四种类型对比与选择
| 维度 | Counter | Gauge | Histogram | Summary |
|---|---|---|---|---|
| 方向 | 只增不减 | 可增可减 | Bucket 是 Counter | 分位数是 Gauge |
| 典型场景 | 请求计数 | 当前温度 | 延迟分布 | 客户端精确分位 |
| 跨实例聚合 | ✅ sum(rate()) |
✅ avg() |
✅ histogram_quantile(sum()) |
❌ 不可聚合 |
| 查询分位数 | ❌ | ❌ | ✅ 服务端计算 | ✅ 客户端计算 |
| CPU 开销 | 极低 | 极低 | 低 | 较高(客户端排序) |
| 推荐度 | 必用 | 必用 | ⭐ 首选 | 仅限单机场景 |
🚨 Summary 的分位数不可聚合! 50 台机器的 P99 平均值 ≠ 全局 P99。需要全局分位数时请用 Histogram。
2. PromQL 查询语言
PromQL 是 Prometheus 的函数式查询语言,所有仪表盘、告警规则都依赖它。
2.1 数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
| Instant Vector(瞬时向量) | 一组时间序列,每个只有一个时间点的值 | http_requests_total |
| Range Vector(区间向量) | 一组时间序列,每个有一段时间范围内的值 | http_requests_total[5m] |
| Scalar(标量) | 单个浮点数 | 3.14 |
| String(字符串) | 字符串值(极少使用) | "hello" |
2.2 选择器与标签匹配
# 精确匹配
http_requests_total{method="GET", status="200"}
# 否定匹配
http_requests_total{method!="GET"}
# 正则匹配
http_requests_total{method=~"GET|POST"}
# 否定正则
http_requests_total{method!~"DELETE|PATCH"}
# 多个条件(AND 关系)
{job=~"node.*", instance=~"10\\.1\\.150\\..*"}💡 正则匹配牢记:=~ 是匹配,!~ 是不匹配。
2.3 Counter 专属:rate() / irate() / increase()
🚨 黄金法则:永远不要直接对 Counter 原始值做查询或告警——进程中累计 3 天跑了 1 亿次请求,原始值没有任何意义。必须用
rate()或increase()转换。
# === rate() — 每秒平均增长率(推荐用于仪表盘和告警)===
rate(http_requests_total[5m])
# === irate() — 瞬时增长率(仅最后两个样本点计算,灵敏度极高)===
irate(http_requests_total[5m])
# === increase() — 时间窗口内总增长量 ===
increase(http_requests_total[1h])| 特性 | rate() |
irate() |
increase() |
|---|---|---|---|
| 计算方式 | 窗口内所有点的平均斜率 | 仅最后两个点 | rate × 窗口秒数 |
| 灵敏度 | 中等 | 极高 | 中等 |
| 曲线平滑度 | 高 | 低(嘈杂) | 高 |
| 适用于告警 | ✅ | ❌ | ⚠️(可用但不如 rate 直观) |
| 适用于图表 | ✅ | ❌ | ✅ |
| 适用于突发检测 | ⚠️ | ✅ | ⚠️ |
💡 时间窗口 ≥ 4× scrape_interval。 比如 scrape_interval=30s,则 [5m] 是合理的最小窗口;用 [2m] 或 [1m] 会产生抖动。
🔬 深入原理: rate() 和 increase() 都采用外推(extrapolation),把数据点布局到窗口的全长。所以 increase() 的结果可能是非整数(如 123.45 个请求),即使原始数据都是整数。这是预期行为。
常用组合:
# 每秒请求数(按状态码分)
sum(rate(http_requests_total[5m])) by (status_code)
# 错误率百分比
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ (sum(rate(http_requests_total[5m])) > 0)
* 100
# APDEX(Apdex 分数)
sum(rate(http_request_duration_seconds_bucket{le="0.5"}[5m]))
/ sum(rate(http_request_duration_seconds_count[5m]))2.4 Gauge 专属:时间聚合函数
# 过去 10 分钟的平均内存
avg_over_time(memory_usage_bytes[10m])
# 过去 1 小时的 CPU 峰值
max_over_time(cpu_usage_percent[1h])
# 过去 1 小时的最小值
min_over_time(free_disk_bytes[1h])
# net change(后值减前值)
delta(queue_size[1h])
# 每秒斜率(线性回归)
deriv(temperature_celsius[1h])
# 预测未来值(线性回归外推)
predict_linear(free_disk_bytes[1h], 3600) # 预测 1 小时后的值🚨
delta()和deriv()不处理计数器重置。只用于 Gauge。对 Counter 用delta()会在重启时产生巨大的假负值。
2.5 Histogram 专属:histogram_quantile()
# P99 延迟(全聚合 —— 最常用的模式)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
# P50 / P95 / P99 同时查询
histogram_quantile(0.50, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
# 按服务分组
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
# 平均延迟(不是分位数,但常用)
rate(http_request_duration_seconds_sum[5m])
/ rate(http_request_duration_seconds_count[5m])🚨 忘记
by (le)必返回 NaN。le标签是 histogram_quantile() 计算分位数的核心,聚合时必须保留。🚨 最高 bucket 不够大时返回
+Inf。 确保有le="+Inf"的 bucket,且最大有限 bucket 覆盖到实际数据范围。
2.6 聚合运算符
# 按标签分组求和
sum(rate(http_requests_total[5m])) by (method, status)
# 排除指定标签后求和
sum without(cpu, mode)(rate(node_cpu_seconds_total[5m]))
# 其他聚合:avg, min, max, count, stddev, stdvar
# topk / bottomk — 取前/后 K 条序列
topk(5, rate(http_requests_total[5m]))
# quantile — 跨序列分位数(注意:不是 histogram_quantile!)
quantile(0.95, rate(http_requests_total[5m]))2.7 运算符与向量匹配
# 算术运算
rate(http_requests_total[5m]) * 60 # 转成每分钟
1 - (node_memory_MemAvailable / node_memory_MemTotal) # 内存使用率
# 比较运算
rate(errors_total[5m]) > 0.1 # 错误率超过 0.1/s
# 布尔运算(and / or / unless)
rate(http_requests_total{status="500"}[5m])
and
rate(http_requests_total{status="200"}[5m]) # 有 500 且也有 200
# on / ignoring — 指定匹配标签
rate(http_requests_total[5m]) * on(instance) group_left
node_memory_MemAvailable_bytes2.8 时间偏移
# 查看 1 小时前的数据
http_requests_total offset 1h
# 与前一日同时段对比
rate(http_requests_total[5m])
/
rate(http_requests_total[5m] offset 1d)2.9 函数速查表
| 函数 | 适用范围 | 返回 | 处理重置 | 告警推荐 |
|---|---|---|---|---|
rate() |
Counter | 每秒速率 | ✅ | ✅ |
irate() |
Counter | 瞬时速率 | ✅ | ❌ |
increase() |
Counter | 总增量 | ✅ | ⚠️ |
resets() |
Counter | 重置次数 | N/A | ❌ |
delta() |
Gauge | 差值 | ❌ | ⚠️ |
deriv() |
Gauge | 斜率/秒 | ❌ | ⚠️ |
predict_linear() |
Gauge | 预测值 | ❌ | ✅ |
avg_over_time() |
Gauge | 窗口均值 | ❌ | ⚠️ |
max_over_time() |
Gauge | 窗口最大值 | ❌ | ⚠️ |
histogram_quantile() |
Histogram | 分位数 | N/A | ✅ |
absent() |
任意 | 是否无数据 | N/A | ✅ |
absent_over_time() |
Range | 窗口内是否无数据 | N/A | ✅ |
changes() |
任意 | 变化次数 | ❌ | ❌ |
sort() / sort_desc() |
任意 | 排序 | ❌ | ❌ |
label_replace() |
任意 | 重命名标签 | ❌ | ❌ |
label_join() |
任意 | 合并标签 | ❌ | ❌ |
vector() |
Scalar | 标量→向量 | ❌ | ❌ |
参考资料: