前言

  • 我看到很多人会这样应用联邦:联邦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分片

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

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