4. 指标定义规范:Metric命名规则、标签设计原则、指标类型选择
指标定义是Exporter开发的核心环节。一个规范的指标定义,需要同时满足三个维度:命名可读、标签可查、类型可用。本章从这三个维度出发,给出可落地的标准化规范。
4.1 Metric命名规则
Prometheus官方推荐使用 snake_case 命名法,Exporter指标命名必须遵循以下层级结构:
<namespace>_<subsystem>_<unit>[_<suffix>]
| 层级 | 说明 | 示例 |
|---|---|---|
| namespace | 应用或领域名称,单数小写 | node、redis、kafka |
| subsystem | 模块或组件名称,可选 | network、memory、disk |
| unit | 指标描述的核心实体 | bytes、requests、errors |
| suffix | 单位后缀,如 _total、_seconds、_bytes |
_total、_count、_bucket |
命名避坑清单:
- 禁止使用大写字母(如
Redis_Memory) - 禁止使用连字符(如
redis-memory) - 禁止以数字开头(如
1st_request) - 禁止使用Prometheus保留后缀以外的自定义后缀
- 单位后缀必须与指标实际单位一致,
_bytes不能用于计数
4.2 标签设计原则
标签是Prometheus多维数据模型的基石。设计不当的标签会导致基数爆炸、查询缓慢、存储膨胀。以下原则必须遵守:
| 原则 | 说明 | 正确示例 | 错误示例 |
|---|---|---|---|
| 有限基数 | 标签值数量应控制在100以内 | status="200" |
user_id="u_12345" |
| 可枚举 | 标签值应来自预定义集合 | method="GET" |
ip="192.168.1.1" |
| 不包含时间戳 | 时间信息应放在时间戳字段 | (不添加时间标签) | timestamp="2025-01-01" |
| 不包含随机值 | 随机ID、UUID、Session等禁止作为标签 | region="us-east" |
session_id="abc123" |
| 标签名语义化 | 使用有业务含义的短名称 | db_name |
attr1 |
标签基数爆炸典型案例: 某团队在
http_requests_total 上添加了 path 标签,包含所有RESTful路径(如 /api/v1/users/12345/profile),导致一周内标签基数从50增长到50万,Prometheus OOM。解决方案:只保留 endpoint 标签(如 /api/v1/users/:id/profile),路径参数通过日志链路追踪。
4.3 指标类型选择
Prometheus提供四种核心指标类型。选择错误会导致查询语义混乱、聚合结果失真。以下给出选择决策树和对比表:
4.4 四种指标类型对比
| 类型 | 适用场景 | 可聚合 | 分位数 | 典型后缀 |
|---|---|---|---|---|
| Counter | 只增不减的累计值:请求数、错误数、写入字节数 | 支持 rate() / increase() |
不支持 | _total |
| Gauge | 可增可减的瞬时值:内存使用率、连接数、温度 | 支持 avg() / max() |
不支持 | 无固定后缀 |
| Histogram | 需要自定义分位数或计算SLA:请求延迟、响应大小 | 支持 histogram_quantile() |
服务端计算 | _bucket、_count、_sum |
| Summary | 已知分位数且客户端计算:延迟百分位、评分分布 | 不支持跨进程聚合 | 客户端计算 | _count、_sum、_created |
实战选择口诀:
“计数用Counter,快照用Gauge;分位未知Histogram,分位已知Summary;聚合查询选Histogram,精确分位选Summary。”
“计数用Counter,快照用Gauge;分位未知Histogram,分位已知Summary;聚合查询选Histogram,精确分位选Summary。”
4.5 指标定义完整示例
以下是一个符合规范的Redis Exporter指标定义片段:
// 命名:redis_memory_used_bytes
// 类型:Gauge
// 标签:db, role
redis_memory_used_bytes{db="0", role="master"} 1048576
// 命名:redis_commands_total
// 类型:Counter
// 标签:command, result
redis_commands_total{command="get", result="success"} 1024
// 命名:redis_request_duration_seconds
// 类型:Histogram
// 标签:command
// Bucket:{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, +Inf}
redis_request_duration_seconds_bucket{command="get", le="0.01"} 500
redis_request_duration_seconds_bucket{command="get", le="+Inf"} 1024
redis_request_duration_seconds_count{command="get"} 1024
redis_request_duration_seconds_sum{command="get"} 12.345
代码审查清单: 每次提交Exporter代码前,对照以下问题检查指标定义:
1. 命名是否包含 namespace 和 unit?
2. 标签基数是否可控?
3. 类型选择是否与指标语义一致?
4. Histogram 的 bucket 边界是否覆盖业务分布?
5. 是否遗漏了
1. 命名是否包含 namespace 和 unit?
2. 标签基数是否可控?
3. 类型选择是否与指标语义一致?
4. Histogram 的 bucket 边界是否覆盖业务分布?
5. 是否遗漏了
_count 和 _sum(对于 Histogram/Summary)?
4.6 标签设计实战案例
以“数据库查询延迟”指标为例,展示标签设计从坏到好的演进过程:
核心原则: 指标标签只承载“用于分组聚合的有限维度”,不承载“用于追踪的无限维度”。无限维度请走日志链路。