乐趣区

关于prometheus:别再乱用prometheus联邦了分享一个multiremoteread的方案来实现prometheus高可用

前言

  • 我看到很多人会这样应用联邦:联邦 prometheus 收集多个采集器的数据
  • 切实看不下上来了,很多小白还在乱用 prometheus 的联邦
  • 其实很多人是想实现 prometheus 数据的可用性,数据分片保留,有个对立的查问中央(小白中的联邦 prometheus)
  • 而且引入 m3db 等反对集群的 tsdb 可能比拟重

    • 具体问题能够看我之前写的文章 m3db 资源开销,聚合降采样,查问限度等注意事项
    • m3db-node oom 追踪和内存分配器代码查看
  • 明天写篇文章剖析下联邦的问题,并给出一个基于全副是 prometheus 的 multi_remote_read 计划

架构图

联邦问题

  • 联邦文档地址

联邦应用样例

  • 实质上就是采集级联
  • 说白了就是 a 从 b,c,d 那里再采集数据过去
  • 能够搭配 match 指定只拉取某些指标
  • 上面就是官网文档给出的样例
scrape_configs:
  - job_name: 'federate'
    scrape_interval: 15s

    honor_labels: true
    metrics_path: '/federate'

    params:
      'match[]':
        - '{job="prometheus"}'
        - '{__name__=~"job:.*"}'

    static_configs:
      - targets:
        - 'source-prometheus-1:9090'
        - 'source-prometheus-2:9090'
        - 'source-prometheus-3:9090'

看下面的样例配置怎么感觉是采集的配置呢

  • 不必狐疑就是,上面看看代码剖析一下

    从上述配置能够看到采集的 path 是 /federate

    // web.go 的 federate Handler
    router.Get("/federate", readyf(httputil.CompressionHandler{Handler: http.HandlerFunc(h.federation),
    }.ServeHTTP))

剖析下联邦函数 说白了就是读取本地存储数据处理


func (h *Handler) federation(w http.ResponseWriter, req *http.Request) {

    // localstorage 的 query
    q, err := h.localStorage.Querier(req.Context(), mint, maxt)

    defer q.Close()
    // 最终发送的 Vector 数组
    vec := make(promql.Vector, 0, 8000)

    hints := &storage.SelectHints{Start: mint, End: maxt}

    var sets []storage.SeriesSet

    set := storage.NewMergeSeriesSet(sets, storage.ChainedSeriesMerge)
    // 遍历存储中的 full series
    for set.Next() {s := set.At()


        vec = append(vec, promql.Sample{Metric: s.Labels(),
            Point:  promql.Point{T: t, V: v},
        })

    for _, s := range vec {
        nameSeen := false
        globalUsed := map[string]struct{}{}
        protMetric := &dto.Metric{Untyped: &dto.Untyped{},
        }
        // Encode 办法依据申请类型编码
                if protMetricFam != nil {if err := enc.Encode(protMetricFam); err != nil {federationErrors.Inc()
                        level.Error(h.logger).Log("msg", "federation failed", "err", err)
                        return
                    }
                }

        }

        protMetric.TimestampMs = proto.Int64(s.T)
        protMetric.Untyped.Value = proto.Float64(s.V)

        protMetricFam.Metric = append(protMetricFam.Metric, protMetric)
    }
    // 
    if protMetricFam != nil {if err := enc.Encode(protMetricFam); err != nil {federationErrors.Inc()
            level.Error(h.logger).Log("msg", "federation failed", "err", err)
        }
    }
}

最终调用压缩函数压缩

type CompressionHandler struct {Handler http.Handler}

// ServeHTTP adds compression to the original http.Handler's ServeHTTP() method.
func (c CompressionHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {compWriter := newCompressedResponseWriter(writer, req)
    c.Handler.ServeHTTP(compWriter, req)
    compWriter.Close()}

如果没有过滤那么只是一股脑把分片的数据集中到了一起,没意义

  • 很多时候是因为数据量太大了,扩散在多个采集器的数据是不能被一个联邦消化的

正确应用联邦的姿态

  • 应用 match 加过滤,将采集数据分位两类

    • 第一类须要再聚合的数据,通过联邦收集在一起

      • 举个例子

        • 只收集中间件的数据的联邦
        • 只收集业务数据的联邦
    • 其余数据保留在采集器本地即可
  • 这样能够在各个联邦上执行 预聚合 alert,使得查问速度晋升

默认 prometheus 是不反对降采样的

  • 能够在联邦配置 scrape_interval 的时候设置的大一点来达到 模仿降采样的目标
  • 实在的降采样须要 agg 算法反对的,比方 5 分钟的数据算平均值、最大值、最小值保留,而不是这种把采集距离调大到 5 分钟的随机选点逻辑

正确实现对立查问的姿态是应用 prometheus multi_remote_read

什么是 remote_read

  • 简略说就是 prometheus 意识到本人本地存储不具备可用性,所以通过反对第三方存储来有余这点的伎俩
  • 配置文档地址

读写都反对的存储

  • AWS Timestream
  • Azure Data Explorer
  • Cortex
  • CrateDB
  • Google BigQuery
  • Google Cloud Spanner
  • InfluxDB
  • IRONdb
  • M3DB
  • PostgreSQL/TimescaleDB
  • QuasarDB
  • Splunk
  • Thanos
  • TiKV

然而这个和咱们明天聊的问题关联在哪里?

multi_remote_read

如果咱们配置了多个 remote_read 接口的话即可实现 multi

remote_read:
  - url: "http://172.20.70.205:9090/api/v1/read"
    read_recent: true
  - url: "http://172.20.70.215:9090/api/v1/read"
    read_recent: true

上述配置代表并发查问两个后端存储,并能够对查问的后果进行 merge

  • merge 有啥用:认为着你们的查问 promql 或者 alert 配置文件无需关怀数据到底存储在哪个存储外面
  • 能够间接应用全局的聚合函数

prometheus 能够 remote_read prometheus 本人

感觉这个特点很多人不晓得,认为 remote_read 必须配置第三方存储如 m3db 等

所以联合上述两个特点就能够用多个采集的 prometheus + 多个无状态的 prometheus query 实现 prometheus 的高可用计划

  • 监控数据存储在多个采集器的本地,能够是机器上的 prometheus
  • 也能够是 k8s 中的 prometheus statefulset
  • prometheus query remote_read 填写多个 prometheus/api/v1/read/ 地址

数据反复怎么办

  • 不必管,下面提到了 query 会做 merge,多个数据只会保留一份
  • 到正能够利用这个特点模仿正本机制:

    • 重要的采集 job 由两个以上的采集 prometheus 采集
    • 查问的时候 merge 数据
    • 能够防止其中一个挂掉时没数据的问题

    那么这种计划的毛病在哪里

  • 并发查问必须要等最慢的那个返回才返回,所以如果有个慢的节点会导致查问速度降落,举个例子

    • 有个美东的节点,网络根底提早是 1 秒,那么所有查问无论返回多快都必须叠加 1 秒的提早
  • 应答重查问时可能会把 query 打挂

    • 但也正是这个特点,会很好的爱护后端存储分片
    • 重查问的基数扩散给多个采集器了
  • 因为是无差别的并发 query,也就是说所有的 query 都会打向所有的采集器,会导致一些采集器总是查问不存在他这里的数据

    • 那么一个关键性的问题就是,查问不存在这个 prometheus 的数据的资源开销到底是多少
    • 据我察看,新版本速度还是很快的阐明资源开销不会在很深的中央才判断出不属于我的数据
    • m3db 有布隆过滤器来避免这个问题
  • 如果想准确把 query 打向数据它的存储分片能够参考我之前写的 route 计划:开源我的项目 : prome-route:应用反向代理实现 prometheus 分片

    • 次要哦,须要特色标签反对,并且数据人造就是离开的!!

能够加一些探活 / 治理采集器的逻辑来欠缺这个计划

退出移动版