本篇是《Prometheus 从入门到生产实践》第 3 / 24 篇。配置以文中版本与环境前提为准,实验和故障均为教学场景。完整程序、配置及校验范围见配套实验包。
Prometheus 的基本存储单元是时间序列。指标名和完整标签集合共同标识一条序列;同一个指标名,只要标签值不同,就是另一条序列。本篇先把数据模型理解清楚,再讨论采集多少指标。

1. 一行样本到底表示什么
ops_demo_requests_total{method="GET",route="/api",code="200"} 120
它表示这组标签对应的累计值为 120,采集时会关联一个时间点。method、route、code 是维度,而不是每个请求的一份事件记录。
Prometheus 通常添加 job、instance 等目标标签。标签缺失、空值以及目标重标记都可能影响查询匹配,写查询前先查看实际存储的标签。
2. 四类常见指标如何选择
| 类型 | 用途 | 常见处理 |
|---|---|---|
| Counter | 只能随事件增长,重启等可重置 | rate、increase,注意 reset |
| Gauge | 可以增减的当前值 | 当前值、聚合、区间趋势 |
| Histogram | 观察值的分布 | 聚合桶、阈值占比、估算分位数 |
| Summary | 次数、总和及客户端计算的分位数 | 分位数通常不能跨实例直接聚合 |
Counter 的当前值不是每秒请求数,Gauge 也不应该随手套 rate。经典直方图和原生直方图的存储与查询表达不同,第九篇会深入说明。定义见 指标类型文档。
3. 基数是维度组合,不是标签键的数量
如果 10 个实例、5 条规范化路由、2 个方法和5类状态同时存在,一项 counter 最多可能形成 500 条组合;再给每次请求加唯一 request_id,就会随着请求量持续产生新序列。
这个乘积是规模估算,不保证所有组合实际存在,也不计入历史 churn。短命目标和不断变动的标签会带来额外开销。
路由用 /users/:id 这种模板而不是 /users/18372,用户、订单和trace标识留在日志或链路。需要关联时可以研究 exemplar,但也要评估数据隐私和后端支持。
4. 命名与单位要让查询可读
时间统一以秒等基础单位表达,字节指标清楚标明 bytes,累计计数常用 total 后缀。不要在同一指标里混合毫秒和秒,或让相同名称在不同环境里代表不同统计口径。
标签值可变化,但标签的业务含义应稳定。把“失败率”记录成 20 还是 0.2,会直接影响告警阈值和图表展示。
检查命名规范可参考 官方命名实践。设计指标时先写一句自然语言定义,包括事件边界、单位、标签和何时递增。
5. 用实验指标计算规模
教学 counter 有两种 code,形成两条;经典直方图每个 code 有三个有限桶、一个 +Inf 桶、sum 和 count,共六条,两种 code 合计十二条;再加一个 inflight gauge,exporter 暴露十五条样本序列。
这只是教学端点的业务指标,不含 Prometheus 自动产生的 up、scrape_duration_seconds 等采集状态。也不是说任意 histogram 永远只有六条。
6. 缺失、零和采集失败不是同一种状态
计数器显式导出 0 表示已知该组合没有事件;不导出某组标签时可能查询为空;抓取失败影响 up 和后续样本可用性,但不能直接伪造业务请求值为零。
练习:打开 /metrics 数业务序列,再查询 count by (__name__) ({job="demo",__name__=~"ops_demo_.+"})。比较预期与实际,解释哪些是业务指标,哪些是抓取过程生成的指标。