4. Prometheus 基础回顾:Metric 类型与 PromQL 聚合算子
在构建 Kubernetes 存储组件的 SLO 与错误预算面板之前,必须牢固掌握 Prometheus 的四种核心 Metric 类型以及 PromQL 的聚合算子。这些基础构件决定了我们如何采集、建模和聚合存储指标(如 PVC 延迟、卷容量、API 调用错误率)。
4.1 四种 Metric 类型对比
Prometheus 客户端库提供四种核心 Metric 类型,每种类型适用于不同的监控场景。下表从语义、典型用途和存储特性三个维度进行对比:
| 类型 | 语义 | 典型用途(存储场景) | 存储特性 |
|---|---|---|---|
| Counter | 只增不减的累计值(重启归零) | CSI 卷挂载请求总数、存储 API 调用次数、磁盘写入字节累计 | 适合用 rate() 或 increase() 计算每秒速率 |
| Gauge | 可增可减的瞬时值 | PVC 当前容量使用率、存储节点在线状态、卷挂载延迟(ms) | 直接使用原始值,或通过 avg_over_time 平滑 |
| Histogram | 观测值分布(桶 + 总和 + 计数) | 存储 I/O 延迟分布、卷扩容耗时分布 | 通过 histogram_quantile() 计算 P99/P50 延迟 |
| Summary | 预计算的分位数(客户端侧) | 存储 API 响应延迟预计算分位数(较少用于存储场景) | 无法聚合,适合已知分位数需求的场景 |
存储场景选型建议: 对于卷延迟 SLO,优先使用 Histogram,因为它支持服务端聚合计算任意分位数;对于卷容量和节点状态,使用 Gauge;对于请求计数和错误计数,使用 Counter。
4.2 Counter 与 Gauge 的 PromQL 操作
Counter 和 Gauge 是面板中最常用的两种类型,它们的 PromQL 操作方式有本质区别:
- Counter 操作: 必须使用
rate()或increase()转换为速率后再使用,否则原始累计值在面板上会呈现单调递增曲线,无法反映当前负载。 - Gauge 操作: 可以直接使用原始值,也可以使用
avg_over_time()、max_over_time()等聚合函数进行时间窗口平滑。
# Counter 示例:计算 CSI 卷挂载请求的每秒速率(过去 5 分钟)
rate(csi_volume_mount_requests_total[5m])
# Gauge 示例:查看当前 PVC 容量使用率(百分比)
(pvc_capacity_used_bytes / pvc_capacity_total_bytes) * 100
# Gauge 示例:过去 1 小时的平均卷延迟
avg_over_time(volume_io_latency_ms[1h])
4.3 Histogram 与 Summary 的 PromQL 操作
Histogram 和 Summary 都用于测量分布,但 PromQL 的使用方式不同:
| 操作 | Histogram 示例 | Summary 示例 |
|---|---|---|
| 计算 P99 延迟 | histogram_quantile(0.99, rate(storage_io_latency_seconds_bucket[5m])) |
storage_api_latency_seconds{quantile="0.99"} |
| 计算平均延迟 | rate(storage_io_latency_seconds_sum[5m]) / rate(storage_io_latency_seconds_count[5m]) |
storage_api_latency_seconds_sum / storage_api_latency_seconds_count |
| 聚合多个实例 | 支持(服务端聚合桶再计算分位数) | 不支持(分位数在客户端预计算,无法聚合) |
关键区别: Summary 的分位数在客户端预计算,无法跨实例聚合;Histogram 的分位数在服务端通过 PromQL 计算,支持聚合。对于 Kubernetes 存储集群的多节点场景,始终优先使用 Histogram。
4.4 PromQL 聚合算子
PromQL 聚合算子用于将多个时间序列合并为单个序列。在存储面板中,我们经常需要按 PVC、StorageClass 或节点维度聚合指标。
4.4.1 常用聚合算子一览
| 算子 | 作用 | 存储面板典型用法 |
|---|---|---|
sum() |
求和 | 所有 PVC 的总容量使用量 |
avg() |
平均值 | 集群平均卷延迟 |
max() / min() |
最大值 / 最小值 | 最慢卷的延迟、最低可用容量 |
count() |
计数 | 处于 Pending 状态的 PVC 数量 |
topk() / bottomk() |
前 K 个 / 后 K 个 | 延迟最高的 Top 5 卷 |
quantile() |
分位数(Gauge 专用) | 卷延迟的 P50 分布(非 Histogram 场景) |
4.4.2 聚合算子与 by / without 子句
聚合算子必须配合 by 或 without 子句指定保留的标签维度:
# 按 storage_class 聚合:每个 StorageClass 的总容量
sum by (storage_class) (pvc_capacity_bytes)
# 按 namespace 和 storage_class 聚合
sum by (namespace, storage_class) (pvc_capacity_bytes)
# 排除 instance 标签:聚合所有实例
sum without (instance) (csi_volume_mount_requests_total)
存储面板最佳实践: 在 SLO 面板中,通常按
namespace、storage_class、persistentvolumeclaim 三个维度聚合。避免过度聚合导致丢失故障定位所需的标签信息。
4.5 Metric 类型与 PromQL 聚合关系图
下图展示了四种 Metric 类型如何通过 PromQL 算子转化为面板可用的指标,以及它们在存储 SLO 计算中的角色:
4.6 存储场景 PromQL 实战示例
以下示例展示了如何将上述知识应用于 Kubernetes 存储组件的面板查询:
# 示例 1:计算每个 StorageClass 的卷挂载错误率(Counter + rate + sum by)
sum by (storage_class) (
rate(csi_volume_mount_errors_total[5m])
)
/
sum by (storage_class) (
rate(csi_volume_mount_requests_total[5m])
)
# 示例 2:计算集群中 PVC 容量使用率超过 80% 的卷数量(Gauge + count by)
count by (namespace) (
(pvc_capacity_used_bytes / pvc_capacity_total_bytes) > 0.8
)
# 示例 3:计算每个卷的 P99 延迟(Histogram + histogram_quantile + rate)
histogram_quantile(
0.99,
sum by (persistentvolumeclaim, le) (
rate(volume_io_latency_seconds_bucket[5m])
)
)
# 示例 4:计算错误预算消耗(Counter + increase + 时间窗口)
1 - (
increase(csi_volume_mount_errors_total[30d])
/
increase(csi_volume_mount_requests_total[30d])
)
关键要点: 在编写存储 SLO 面板的 PromQL 时,始终注意:
1. Counter 必须用
2. Histogram 的
3. 聚合时使用
4. 错误预算计算使用
1. Counter 必须用
rate() 或 increase() 包裹;2. Histogram 的
histogram_quantile() 必须配合 rate() 使用桶的增量;3. 聚合时使用
by 保留故障定位所需的标签(如 persistentvolumeclaim、namespace);4. 错误预算计算使用
increase() 在 SLO 时间窗口(如 30 天)内累计错误和请求总数。