3. Prometheus 数据模型:Metric 类型、Label 与命名最佳实践
Prometheus 的数据模型是构建可靠监控与误差预算台账的基石。理解 Metric 类型、Label 的作用以及命名规范,能够帮助你设计出既精确又易于维护的查询语句。本节将系统梳理这三大核心概念。
3.1 Metric 类型:四种核心指标
Prometheus 客户端库提供了四种核心 Metric 类型,每种类型对应不同的数据采集与查询语义。在误差预算场景中,Counter 和 Histogram 是最常用的类型。
| 类型 | 值特征 | 典型用途 | 误差预算相关 |
|---|---|---|---|
| Counter | 只增不减(重启归零) | 请求总数、错误总数、CPU 时间 | 计算错误率、SLI 分母/分子 |
| Gauge | 可增可减,反映当前值 | 内存使用量、队列深度、连接数 | 实时资源水位,辅助排障 |
| Histogram | 分桶计数 + 总和 + 总数 | 请求延迟分布、响应大小分布 | 计算延迟 SLI(如 p99 < 200ms) |
| Summary | 预计算分位数 + 总和 + 总数 | 延迟分位数(客户端计算) | 替代 Histogram,但无法聚合 |
histogram_quantile() 计算,支持聚合;Summary 的分位数在客户端预计算,无法跨实例聚合。在误差预算台账中,优先使用 Histogram 以保证全局 SLO 计算的准确性。
3.1.1 Counter:单调递增计数器
Counter 是最基础的指标类型,代表一个只能增加的累积值。在 PromQL 中,通常使用 rate() 或 increase() 函数将其转换为每秒速率或增量,用于计算错误率或吞吐量。
# 计算过去 5 分钟的平均每秒错误率
rate(http_requests_total{status="500"}[5m])
# 计算过去 1 小时的总错误数(用于误差预算消耗)
increase(http_requests_total{status="500"}[1h])
3.1.2 Gauge:可上下波动的瞬时值
Gauge 用于测量可以任意变化的瞬时值,如内存使用率、CPU 温度、并发连接数。在误差预算场景中,Gauge 通常用于监控资源饱和度,辅助判断容量是否影响 SLO。
# 当前内存使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
3.1.3 Histogram:分桶分布与延迟 SLI
Histogram 将观测值(如请求延迟)分配到可配置的桶(bucket)中,同时记录所有观测值的总和与总数。它是实现延迟 SLI 的标准方式。
# 定义 Histogram 指标(示例:客户端埋点)
# http_request_duration_seconds_bucket{le="0.1"} 10
# http_request_duration_seconds_bucket{le="0.5"} 20
# http_request_duration_seconds_bucket{le="1.0"} 25
# http_request_duration_seconds_sum 12.5
# http_request_duration_seconds_count 25
# 计算 p99 延迟(服务端 PromQL)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
3.1.4 Summary:客户端预计算分位数
Summary 与 Histogram 类似,但分位数在客户端计算并暴露。由于无法在服务端进行聚合,Summary 不适合用于跨实例的全局 SLO 计算,但在需要精确分位数且不需要聚合的场景下仍有价值。
histogram_quantile() 无法对 Summary 指标进行计算,且 Summary 的分位数在聚合后会失去意义。
3.2 Label 的作用:多维数据模型的核心
Label 是 Prometheus 数据模型的灵魂。每个 Metric 可以附加一组键值对 Label,用于标识不同的维度,如 method、status、instance、service。Label 使得同一指标可以按任意维度进行聚合、过滤和分组。
3.2.1 Label 的最佳实践
- 高基数 Label 谨慎使用: 如
user_id、request_id、ip等取值无限的 Label 会导致时序数据库膨胀,影响查询性能。建议将高基数数据通过日志系统处理。 - 统一 Label 命名: 团队内约定统一的 Label 名称,如统一使用
service而非svc或app,避免查询时混淆。 - 利用 Label 做多维度 SLO: 通过
status、method、endpoint等 Label,可以分别计算不同维度的错误预算,实现精细化治理。
# 按 service 和 status 分组计算错误率
sum by (service, status) (rate(http_requests_total[5m]))
3.3 Metric 命名最佳实践
良好的命名规范能够提升指标的可读性和可发现性。Prometheus 官方推荐遵循以下模式:
| 规范 | 说明 | 示例 |
|---|---|---|
| 命名空间前缀 | 使用 namespace_ 前缀区分不同组件 |
prometheus_http_requests_total |
| 下划线分隔 | 单词间使用下划线,避免驼峰或连字符 | http_request_duration_seconds |
| 单位后缀 | 指标名末尾包含单位(如 _seconds、_bytes、_total) |
node_memory_MemAvailable_bytes |
| 类型后缀 | Counter 以 _total 结尾;Histogram 桶以 _bucket 结尾 |
http_requests_total、http_request_duration_seconds_bucket |
| 避免冗余 | 不要在指标名中重复 Label 信息 | 使用 http_requests_total{method="GET"} 而非 http_requests_total_get |
sli:http_requests_total(总请求数)、sli:http_requests_errors_total(错误请求数)、sli:http_request_duration_seconds_bucket(延迟分布)。这样在编写 PromQL 时可以通过正则匹配快速筛选。
3.4 综合示例:误差预算中的 Metric 与 Label 应用
假设我们为一个 Web 服务定义 99% 可用性 SLO,使用以下指标结构:
# 指标定义
# HELP sli_http_requests_total 总请求数
# TYPE sli_http_requests_total counter
sli_http_requests_total{service="web", endpoint="/api/v1/users", method="GET"} 1000
# HELP sli_http_requests_errors_total 错误请求数(status >= 500)
# TYPE sli_http_requests_errors_total counter
sli_http_requests_errors_total{service="web", endpoint="/api/v1/users", method="GET"} 5
# HELP sli_http_request_duration_seconds 请求延迟分布
# TYPE sli_http_request_duration_seconds histogram
sli_http_request_duration_seconds_bucket{service="web", le="0.1"} 800
sli_http_request_duration_seconds_bucket{service="web", le="0.5"} 950
sli_http_request_duration_seconds_bucket{service="web", le="1.0"} 990
sli_http_request_duration_seconds_bucket{service="web", le="+Inf"} 1000
sli_http_request_duration_seconds_sum{service="web"} 120.5
sli_http_request_duration_seconds_count{service="web"} 1000
通过 Label service、endpoint、method,我们可以灵活地计算不同维度的错误预算消耗:
# 计算整个服务的错误率(过去 1 小时)
sum(rate(sli_http_requests_errors_total[1h]))
/
sum(rate(sli_http_requests_total[1h]))
# 按 endpoint 分组计算错误率
sum by (endpoint) (rate(sli_http_requests_errors_total[1h]))
/
sum by (endpoint) (rate(sli_http_requests_total[1h]))
# 计算 p99 延迟(过去 5 分钟)
histogram_quantile(0.99, rate(sli_http_request_duration_seconds_bucket[5m]))
rate() 只能用于 Counter),而 Label 决定了你能从哪些维度进行聚合与过滤。两者结合,才能构建出精确的误差预算台账。