<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          別再亂用 Prometheus 聯(lián)邦了,分享一個(gè) Prometheus 高可用新方案

          共 8861字,需瀏覽 18分鐘

           ·

          2021-06-17 22:55

          作者 | 浪子燕青燕小乙

          來源 | https://zhuanlan.zhihu.com/p/368868988


          前言

          • 我看到很多人會這樣使用聯(lián)邦:聯(lián)邦 prometheus 收集多個(gè)采集器的數(shù)據(jù)

          • 實(shí)在看不下下去了,很多小白還在亂用prometheus的聯(lián)邦

          • 其實(shí)很多人是想實(shí)現(xiàn) prometheus 數(shù)據(jù)的可用性,數(shù)據(jù)分片保存,有個(gè)統(tǒng)一的查詢地方(小白中的聯(lián)邦 prometheus)

          • 而且引入 m3db 等支持集群的 tsdb 可能比較重

          • 具體問題可以看我之前寫的文章 m3db 資源開銷,聚合降采樣,查詢限制等注意事項(xiàng)[1]

            • m3db-node oom 追蹤和內(nèi)存分配器代碼查看[2]
          • 今天寫篇文章分析下聯(lián)邦的問題,并給出一個(gè)基于全部是 prometheus 的multi_remote_read方案

          架構(gòu)圖

          騰訊試點(diǎn)強(qiáng)制6點(diǎn)下班!標(biāo)志著反996、反內(nèi)卷的第一槍嗎?

          聯(lián)邦問題

          • 聯(lián)邦文檔地址[3]

          聯(lián)邦使用樣例

          • 本質(zhì)上就是采集級聯(lián)
          • 說白了就是 a 從 b,c,d 那里再采集數(shù)據(jù)過來
          • 可以搭配 match 指定只拉取某些指標(biāo)
          • 下面就是官方文檔給出的樣例
          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))

          分析下聯(lián)邦函數(shù) 說白了就是讀取本地存儲數(shù)據(jù)處理

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

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

              defer q.Close()
              // 最終發(fā)送的Vector 數(shù)組
              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方法根據(jù)請求類型編碼
                          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)
                  }
              }
          }

          最終調(diào)用壓縮函數(shù)壓縮

          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()
          }

          如果沒有過濾那么只是一股腦把分片的數(shù)據(jù)集中到了一起,沒意義。很多時(shí)候是因?yàn)閿?shù)據(jù)量太大了,分散在多個(gè)采集器的數(shù)據(jù)是不能被一個(gè)聯(lián)邦消化的。

          正確使用聯(lián)邦的姿勢

          • 使用 match 加過濾,將采集數(shù)據(jù)分位兩類

          • 第一類需要再聚合的數(shù)據(jù),通過聯(lián)邦收集在一起

            • 只收集中間件的數(shù)據(jù)的聯(lián)邦 只收集業(yè)務(wù)數(shù)據(jù)的聯(lián)邦
            • 舉個(gè)例子
            • 其余數(shù)據(jù)保留在采集器本地即可
          • 這樣可以在各個(gè)聯(lián)邦上執(zhí)行預(yù)聚合alert,使得查詢速度提升

          默認(rèn) prometheus 不支持降采樣

          • 可以在聯(lián)邦配置 scrape_interval 的時(shí)候設(shè)置的大一點(diǎn)來達(dá)到 模擬降采樣的目的
          • 真實(shí)的降采樣需要 agg 算法支持的,比如 5 分鐘的數(shù)據(jù)算平均值、最大值、最小值保留,而不是這種把采集間隔調(diào)大到 5 分鐘的隨機(jī)選點(diǎn)邏輯

          正確實(shí)現(xiàn)統(tǒng)一查詢的姿勢

          什么是 remote_read

          • 簡單說就是 prometheus 意識到自己本地存儲不具備高可用性,所以通過支持第三方存儲來補(bǔ)足這點(diǎn)的手段
          • 配置文檔地址[4]

          讀寫都支持的存儲

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

          但是這個(gè)和我們今天聊的問題關(guān)聯(lián)在哪里?,往下看你就知道了

          multi_remote_read

          如果我們配置了多個(gè) remote_read 接口的話即可實(shí)現(xiàn) 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

          上述配置代表并發(fā)查詢兩個(gè)后端存儲,并可以對查詢的結(jié)果進(jìn)行 merge

          merge 有啥用:你們的查詢 promql 或者 alert 配置文件就無需關(guān)心數(shù)據(jù)到底存儲在哪個(gè)存儲里面 ,可以直接使用全局的聚合函數(shù)

          prometheus 可以 remote_read prometheus 自己

          感覺這個(gè)特點(diǎn)很多人不知道,以為 remoteread 必須配置第三方存儲如 m3db 等,其實(shí) p 也可以 remote_wirte 自己,只不過需要開啟 --enable-feature=remote-write-receiver

          高可用方案

          所以結(jié)合上述兩個(gè)特點(diǎn)就可以用多個(gè)采集的 prometheus + 多個(gè)無狀態(tài)的 prometheus query 實(shí)現(xiàn) prometheus 的高可用方案

          • 監(jiān)控?cái)?shù)據(jù)存儲在多個(gè)采集器的本地,可以是機(jī)器上的 prometheus
          • 也可以是 k8s 中的 prometheus statefulset
          • prometheus query remote_read 填寫多個(gè)prometheus的/api/v1/read/地址

          數(shù)據(jù)重復(fù)怎么辦

          不用管,上面提到了 query 會做 merge,多個(gè)數(shù)據(jù)只會保留一份

          可以利用這個(gè)特點(diǎn)模擬副本機(jī)制:

          • 重要的采集 job 由兩個(gè)以上的采集 prometheus 采集
          • 查詢的時(shí)候 merge 數(shù)據(jù)
          • 可以避免其中一個(gè)掛掉時(shí)沒數(shù)據(jù)的問題

          這種方案的缺點(diǎn)

          并發(fā)查詢必須要等最慢的那個(gè)返回才返回,所以如果有個(gè)慢的節(jié)點(diǎn)會導(dǎo)致查詢速度下降,舉個(gè)例子:

          有個(gè)美東的節(jié)點(diǎn),網(wǎng)絡(luò)基礎(chǔ)延遲是 1 秒,那么所有查詢無論返回多快都必須疊加 1 秒的延遲。

          應(yīng)對重查詢時(shí)可能會把 query 打掛。

          但也正是這個(gè)特點(diǎn),會很好的保護(hù)后端存儲分片,重查詢的基數(shù)分散給多個(gè)采集器了。

          由于是無差別的并發(fā) query,也就是說所有的 query 都會打向所有的采集器,會導(dǎo)致一些采集器總是查詢不存在他這里的數(shù)據(jù)

          那么一個(gè)關(guān)鍵性的問題就是,查詢不存在這個(gè) prometheus 的數(shù)據(jù)的資源開銷到底是多少?據(jù)我觀察,新版本速度還是很快的說明資源開銷不會在很深的地方才判斷出不屬于我的數(shù)據(jù)。

          m3db 有布隆過濾器來防止這個(gè)問題。

          如果想精確把 query 打向數(shù)據(jù)它的存儲分片可以參考我之前寫的 route 方案:開源項(xiàng)目 : prome-route:使用反向代理實(shí)現(xiàn) prometheus 分片[7]

          主要哦,需要特征標(biāo)簽支持,并且數(shù)據(jù)天然就是分開的!!

          忘了說了,這個(gè)方案還有個(gè)缺點(diǎn)就是重查詢沒控制好容易把你的采集器打掛了

          腳注

          [1]m3db 資源開銷,聚合降采樣,查詢限制等注意事項(xiàng): https://zhuanlan.zhihu.com/p/359551116

          [2]m3db-node oom 追蹤和內(nèi)存分配器代碼查看: https://zhuanlan.zhihu.com/p/183815841

          [3]聯(lián)邦文檔地址: https://prometheus.io/docs/prometheus/latest/federation/

          [4]配置文檔地址: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_read

          [5]InfluxDB: https://docs.influxdata.com/influxdb/v1.8/supported_protocols/prometheus/

          [6]M3DB: https://m3db.io/docs/integrations/prometheus/

          [7]開源項(xiàng)目 : prome-route:使用反向代理實(shí)現(xiàn) prometheus 分片: https://zhuanlan.zhihu.com/p/231914857


          往期推薦

          騰訊試點(diǎn)強(qiáng)制6點(diǎn)下班!標(biāo)志著反996、反內(nèi)卷的第一槍嗎?

          像Swing這種已經(jīng)不太用的技術(shù),大學(xué)還在教,到底要不要學(xué)?

          改造了以前寫的數(shù)據(jù)脫敏插件,更好用了

          如何把Spring Boot的Jar包做成exe?超詳細(xì)教程來了!

          用好 Spring AOP,天降大鍋從容應(yīng)對!



          喜歡本文歡迎轉(zhuǎn)發(fā),關(guān)注我訂閱更多精彩

          關(guān)注我回復(fù)「加群」,加入Spring技術(shù)交流群

          瀏覽 131
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  全国最大色综合网 | 91蝌蚪| 亚洲人在线观看 | 婷婷五月天色色 | 91精品老司机 |