快照直方图是 Gauge,不是 Counter
一个标量指标无法描述变化中的总体分布。一个 30 分钟事务与一百个 18 秒事务的总年龄相同,但数量、最大年龄和运维影响不同。
状态: 已随 v1.4.0 发布。
决策日期: 2026-07-11;2026-07-17 修订。
最后核验: 2026-10-13。
范围: 稳定版v1.4.1的HISTOGRAM列与pg_xact_age采集器,并对照开发提交c0ba58a核验。
交付进度: 已实现、合并、打标签并发布软件包。针对性本地测试已通过;部署与生产运行未核验。
PG Exporter 快照直方图对一次 SQL 执行返回的观测值分组。每次执行都重建分布。由于值可能下降,桶、计数和总和都以 Gauge 序列输出。
时间语义
事务开始时进入总体,随时间增长移入更大的年龄桶,结束时离开总体。这与持续累计事件的 Histogram 不同。
输出沿用常见的桶结构:
这三个指标族都是 Gauge。桶内计数按当前快照的上界累计,不跨抓取累计。直接使用 histogram_quantile():
当前平均年龄由总和除以计数得到:
不要对这些快照序列使用 rate()、irate() 或 increase()。这些函数会把数值下降解释为计数器重置。
配置与 SQL
用 usage: HISTOGRAM 声明观测列,并指定桶上界:
每个非 NULL 值是一次观测。完整标签元组相同的行归入同一分布;多个 Histogram 列独立聚合。
桶包含上界,边界必须有限且严格递增。配置加载时拒绝空列表、重复值、NaN 和无穷值。PG Exporter 自动追加 +Inf。le 标签及生成的 _bucket、_count、_sum 名称为保留名称,冲突配置会被拒绝。
scale 在分桶和求和前生效。时间戳与布尔值沿用标量转换规则,不进行缩放。显式 default 将 NULL 转为观测值;未指定时忽略 NULL。
查询、缓存与失败行为
每次 SQL 执行都从空累加器开始。PG Exporter 对观测分组、计算累计桶,并在读完全部结果后发布指标。
查询出错、缺少必需列或出现非有限观测值时,整份查询结果都被拒绝,包括同一查询的标量指标。刷新失败会将缓存替换为空结果,不保留上一份分布。
缓存命中直接返回上一份结果,不追加观测。下一次 SQL 执行从零开始。重载丢弃旧采集器和缓存,包括旧桶布局。
备选方案与非目标
prometheus.NewConstHistogram将数据标为 Counter Histogram,其时间语义不适合变化中的 SQL 总体。- OpenMetrics GaugeHistogram 能直接表达该语义,但需要为此功能改变输出协议。显式 Gauge 可沿用经典文本端点。
- Native Histogram 解决存储和分辨率问题,不改变观测是事件还是当前总体这一事实。
- 在 SQL 中预聚合桶,会让每个采集器重复分组逻辑。
- 跨抓取保留观测需要事件身份、重启处理和去重。持久事件采集不在本设计范围内;日志 Histogram 使用独立契约。
参考采集器与验证
pg_xact_age 按数据库统计未结束事务的年龄和事务内空闲时长,只选择客户端后端,TTL 为 10 秒。其桶边界支持计算当前分位数、超过阈值的数量和平均年龄。
以下 pgbench 脚本产生多档查询时长和事务内空闲时长。可在测试数据库中运行,观察事务进入和离开各桶:
实现与测试覆盖多个 Histogram 列独立聚合、NULL、缩放、桶边界、查询失败、缓存复用、确定性输出、并发采集与重载。
运维影响
Exporter 无需保存事件历史,就能提供可聚合的当前分布。虽然序列使用常见 Histogram 后缀,仪表盘查询仍须遵循快照语义。
完整语法见采集器配置,发布内容见 v1.4.0。普通累计 Histogram 的查询方法见 Prometheus Histograms and summaries。