counter、gauge、histogram 各自该用在什么地方?gauge 会漏掉尖峰吗?进程重启 counter 归零怎么办?为什么不能把各实例的 p99 求平均?对 gauge 用 rate 会怎样?这篇用 Prometheus 3.15.0 逐项量出来。
指标 | 抓到的样本数 | 结果 | 备注 ---------------------------+--------+-------------------+-------------------- gauge inflight | 20 个样本 | 4 个样本是 100 | max_over_time = 100 counter busy_seconds_total | 20 个样本 | increase = 19.9 s | 应用实际在尖峰里的时间 20.3 s 共 10 个尖峰,每个 2 s;抓取间隔 5 s,一个 2 s 的尖峰被某次抓取碰上的概率约 2/5。gauge 只记录抓取那一刻的值,没碰上的尖峰就看不到;counter 记录累计量,两次抓取之间发生的变化会在下一次抓取时全部体现,increase 能还原总量(counter 在抓取边界处有外推的误差)
gauge 只记录抓取时刻的值,两次抓取之间的尖峰会漏掉;counter 的累计量能还原总量。
计算方式 | 结果 -------------------------------+----- 最后一个样本 − 第一个样本 | 1600 按重置规则手算:(最后 − 第一个) + 重置前的最后一个值 | 3600 increase(requests_total[2m]) | 3685 rate(requests_total[2m]) × 120 | 3685 应用实际处理的请求数 | 4000 抓到 39 个样本,第一个样本 400,最后一个样本 2000;样本序列里检测到的“值变小”的位置:[(2000.0, 100.0)]。increase() 和 rate() 把“值变小”当作 counter 重置,重置之前的值也算进去,所以比“最后 − 第一个”大得多;它们和手算值的差别来自窗口边界的外推;手算值也比应用实际处理的少,因为第一个样本之前的增量不在样本里
increase() / rate() 把值变小当作重置,把重置之前的值算进去;直接相减会少算。
计算方式 | p99(ms) ---------------------------------------------------------+-------- 所有 20000 个请求的真实 p99 | 508.7 A 自己的 p99 | 510.1 B 自己的 p99 | 54.2 两个 p99 取平均(PromQL avg(req_p99_ms)) | 282.2 两个 p99 按请求量加权平均(计算) | 464.5 histogram_quantile(0.99, sum by (le) (increase(bucket))) | 732.6 预先算好的分位数不能求平均:不管是简单平均还是按请求量加权,都不等于合并后的真实 p99;histogram 的桶是计数,可以先相加再估计分位数,但估计值是在桶内线性插值得到的:这里慢请求(500~520 ms)都落在 (500, 1000] 这个宽桶里,插值的结果和真实值差得比较多(见下一篇)
预先算好的分位数不能平均;histogram 的桶可以相加,但估计值取决于桶的划分。
PromQL | 结果
----------------------------------------+-------
rate(hits_total[30s])(每秒 +10 的 counter) | 9.31
rate(level[30s])(对 gauge 用 rate) | 14.41
deriv(level[30s]) | -1.25
delta(level[30s]) | -22.76
level 当前值 | 12
rate() 是为 counter 设计的:它把“值变小”当作重置,gauge 下降的那一段会被当成重置、从 0 重新算;对 gauge 应该用 deriv()(最小二乘斜率)或 delta()(首尾差)
ERRORS {}Prometheus 不强制类型:rate() 用在 gauge 上不会报错,但结果没有意义。