Prometheus笔记

Prometheus metrics 名称必须满足: [a-zA-Z_:][a-zA-Z0-9_:]* label 名必须满足 [a-zA-Z0-9_]*

Prometheus远程存储优化

Prometheus 以每两个小时为一个块,存储到磁盘中,内存保存近两个小时的内容,同时也会写 WAL(write-ahead-log),预写日志文件wal以128MB的段存储在目录中。这些文件包含尚未压缩的原始数据,因此它们比常规的块文件要大。Prometheus将至少保留3个预写日志文件,但是高流量服务器可能会看到三个以上的WAL文件,因为它需要保留至少两个小时的原始数据。

这些块会在后台被压缩成更大的块以节省磁盘,最大长度取决于 storage.tsdb.max-block-duration 参数的设置,默认为保留时间的 10%。 一般来说 storage.tsdb.max-block-duration = storage.tsdb.min-block-duration = 2h 就相当于禁用了压缩功能, 但是别让它们低于 2h,否则有以下的问题:

  • 落盘过于频繁,这会很大程度影响 Promethues 的吞吐量。
  • 由于 WAL 和落盘之前的内存都需要保留两个小时,所以这部分的内存是没办法释放的。

注意 storage.tsdb.max-block-durationstorage.tsdb.min-block-duration 指的都是落盘后的块大小,在内存中用于存储最近两小时数据的内存是不可控的,Prometheus 会在落盘后在后台再去压缩合并这些数据。

参考Remote write tuning

rate vs irate

它们都用于计算一个时间区间内指标的每秒变化率,两者的决定性差别在于:

  • rate 使用整个时间区间所有点计算出平均变化速率,它会削平峰值
  • irate 使用时间区间内最后的两个数据点作为变化速率

从它们两者的计算公式我们可以得到以下推论:

  • 当选择的计算区间内仅仅包含两个数据点时,rate 和 irate 没有区别
  • 我们使用 rate 来查看某个数据在较长一段时间内的变化趋势,它会消除一些细节防止影响趋势的展示
  • 使用 irate 来查看某个数据在一段时间内的细小抖动和完整的变化。
  • 使用 rate 时尽量选择较长的时间,而 irate 则反之(太长会丢失很多变化)

relabel_config vs metric_relabel_configs

relabel_config 发生在 metric_relabel_configs,通常用于挑选 target

如何处理prometheus 的返回结果

promehtues的返回结果是异构的,类似 [1610589855, "11.778672386876817"],除了定义异构结构体外,看了下 client 的代码,原来使用了如下的方式实现:

// SamplePair pairs a SampleValue with a Timestamp.
type SamplePair struct {
	Timestamp Time
	Value     SampleValue
}

// MarshalJSON implements json.Marshaler.
func (s SamplePair) MarshalJSON() ([]byte, error) {
	t, err := json.Marshal(s.Timestamp)
	if err != nil {
		return nil, err
	}
	v, err := json.Marshal(s.Value)
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (s *SamplePair) UnmarshalJSON(b []byte) error {
	v := [...]json.Unmarshaler{&s.Timestamp, &s.Value}
	return json.Unmarshal(b, &v)
}

它将两个字段重组成了一个 json.Unmarshaler 数组,然后用它来接受结果集。

使用 Promehtues 求取一段时间内的最大值

可以使用 max_over_time(query_range[range]) ,请求最大值时为了只返回一个点,可以使用 query 接口,而不是 query_range

Prometheus 的陈旧性( Staleness )

Prometheus 使用 Stale 机制来标识那些已经不再变化了的 TimeSeries,当它被标记为 stable or 在时间点之前的 5分钟(默认值) 内找不到数据点话,在图表上它会立即消失,具体逻辑如下:

  • 如果 target 不再暴露新的 sample,那么 timeseries 会被标记为 stale
  • 如果 target 被移除,那么不久后 timeseries 会被标记为 stale
  • 如果被标记了的时序又产生了新的 sample 那么它会回归 normal 状态
  • 对于自身携带了 timestamp 的 sample,不会应用 Stable 机制,仅有 5 分钟 的阈值限制

以上点可以参考官方文档 (staleness)(https://prometheus.io/docs/prometheus/latest/querying/basics/#staleness)。

这也就是为什么我们有时会看到某个时序已经停止了产生新样本,但是我们依然可以查询到它。

Promehtues 的服务发现

Prometheus抽象了服务发现的接口,只要实现起机制就可以为 Prometheus 实现新的服务发现,文档可以参考 discovery

这里只说明几个遇到过的问题:

  • 当使用 k8s 的 pod 服务发现时,pod 的容器定义最好自己携带端口,否则将会生成一个不带端口的 __address__

直方图与百分位数

分位数(quantile)是指将范围划为等分的连续区间,比如常见的二分位,那么分割点就是中位数,当进行百分位时则被称为 percentile,统计里面经常出现的名词 P99, P90 等等即 99% 90%,比如 P99=5 即代表样本中的 99% 都小于 5 Proemethues 有个函数 ``