高可用prometheus:thanos 實踐

背景

prometheus 使用心得文章中有簡單提到prometheus 的高可用方案,嘗試了聯邦、remote write 以後,咱們最終選擇了 thanos 做爲監控配套組件,利用其全局視圖來管理咱們的多地域/上百個集羣的監控數據。本文主要介紹 thanos 的一些組件使用和心得體會。html

prometheus官方的高可用有幾種方案:node

  1. HA:即兩套 prometheus 採集徹底同樣的數據,外邊掛負載均衡
  2. HA + 遠程存儲:除了基礎的多副本prometheus,還經過Remote write 寫入到遠程存儲,解決存儲持久化問題
  3. 聯邦集羣:即federation,按照功能進行分區,不一樣的 shard 採集不一樣的數據,由Global節點來統一存放,解決監控數據規模的問題。

使用官方建議的多副本 + 聯邦仍然會遇到一些問題,本質緣由是prometheus的本地存儲沒有數據同步能力,要在保證可用性的前提下再保持數據一致性是比較困難的,基本的多副本 proxy 知足不了要求,好比:git

  • prometheus集羣的後端有 A 和 B 兩個實例,A 和 B 之間沒有數據同步。A 宕機一段時間,丟失了一部分數據,若是負載均衡正常輪詢,請求打到A 上時,數據就會異常。
  • 若是 A 和 B 的啓動時間不一樣,時鐘不一樣,那麼採集一樣的數據時間戳也不一樣,就多副本的數據不相同
  • 就算用了遠程存儲,A 和 B 不能推送到同一個 tsdb,若是每人推送本身的 tsdb,數據查詢走哪邊就是問題
  • 官方建議數據作Shard,而後經過federation來實現高可用,可是邊緣節點和Global節點依然是單點,須要自行決定是否每一層都要使用雙節點重複採集進行保活。也就是仍然會有單機瓶頸。
  • 另外部分敏感報警儘可能不要經過global節點觸發,畢竟從Shard節點到Global節點傳輸鏈路的穩定性會影響數據到達的效率,進而致使報警實效下降。

目前大多數的 prometheus 的集羣方案是在存儲、查詢兩個角度上保證數據的一致:github

  • 存儲角度:若是使用 remote write 遠程存儲, A 和 B後面能夠都加一個 adapter,adapter作選主邏輯,只有一份數據能推送到 tsdb,這樣能夠保證一個異常,另外一個也能推送成功,數據不丟,同時遠程存儲只有一份,是共享數據。方案能夠參考這篇文章
  • 存儲角度:仍然使用 remote write 遠程存儲,可是 A 和 B 分別寫入 tsdb1 和 tsdb2 兩個時序數據庫,利用sync的方式在 tsdb1 和2 以前作數據同步,保證數據是全量的。
  • 查詢角度:上邊的方案須要本身實現,有侵入性且有必定風險,所以大多數開源方案是在查詢層面作文章,好比thanos 或者victoriametrics,仍然是兩份數據,可是查詢時作數據去重和join。只是 thanos是經過 sidecar 把數據放在對象存儲,victoriametrics是把數據remote write 到本身的 server 實例,但查詢層 thanos-query 和victor的 promxy的邏輯基本一致,都是爲全局視圖服務

實際需求

隨着咱們的集羣規模愈來愈大,監控數據的種類和數量也愈來愈多:如master/node 機器監控、進程監控、4 大核心組件的性能監控,pod 資源監控、kube-stats-metrics、k8s events監控、插件監控等等。除了解決上面的高可用問題,咱們還但願基於 prometheus 構建全局視圖,主要需求有:web

  • 長期存儲:1 個月左右的數據存儲,天天可能新增幾十G,但願存儲的維護成本足夠小,有容災和遷移。考慮過使用 influxdb,但influxdb沒有現成的集羣方案,且須要人力維護。最好是存放在雲上的 tsdb 或者對象存儲、文件存儲上。
  • 無限拓展:咱們有300+集羣,幾千節點,上萬個服務,單機prometheus沒法知足,且爲了隔離性,最好按功能作 shard,如 master 組件性能監控與 pod 資源等業務監控分開、主機監控與日誌監控也分開。或者按租戶、業務類型分開(實時業務、離線業務)。
  • 全局視圖:按類型分開以後,雖然數據分散了,但監控視圖須要整合在一塊兒,一個 grafana 裏 n個面板就能夠看到全部地域+集羣+pod 的監控數據,操做更方便,不用多個 grafana 切來切去,或者 grafana中多個 datasource 切來切去。
  • 無侵入性:不要對已有的 prometheus 作過多的修改,由於 prometheus 是開源項目,版本也在快速迭代,咱們最先使用過 1.x,可1.x 和 2.x的版本升級也就不到一年時間,2.x 的存儲結構查詢速度等都有了明顯提高,1.x 已經沒人使用了。所以咱們須要跟着社區走,及時迭代新版本。所以不能對 prometheus 自己代碼作修改,最好作封裝,對最上層用戶透明。

在調研了大量的開源方案(cortex/thanos/victoria/..)和商業產品以後,咱們選擇了 thanos,準確的說,thanos只是監控套件,與 原生prometheus 結合,知足了長期存儲+ 無限拓展 + 全局視圖 + 無侵入性的需求。sql

thanos 架構

thanos 的默認模式:sidecar 方式docker


除了 這個sidecar 方式,thanos還有一種不太經常使用的reviver 模式,後面會提到。數據庫

Thanos是一組組件,在官網上能夠看到包括:json

  • Bucket
  • Check
  • Compactor
  • Query
  • Rule
  • Sidecar
  • Store

除了官方提到的這些,其實還有:後端

  • receive
  • downsample

看起來組件不少,但其實部署時二進制只有一個,很是方便。只是搭配不一樣的參數實現不一樣的功能,如 query 組件就是 ./thanos query,sidecar 組件就是./thanos sidecar,組件all in one,也就是代碼也只有一份,體積很小。

其實核心的sidecar+query就已經能夠運行,其餘的組件只是爲了實現更多的功能

最新版 thanos 在 這裏下載release,對於 thanos這種仍然在修bug、迭代功能的軟件,有新版本就不要用舊的。

組件與配置

下面會介紹如何組合thanos組件,來快速實現你的 prometheus 高可用,由於是快速介紹,和官方的 quick start有一部分雷同,且本文截止2020.1 月的版本,不知道之後會thanos 會迭代成什麼樣子

第 1 步:確認已有的 prometheus

thanos 是無侵入的,只是上層套件,所以你仍是須要部署你的 prometheus,這裏再也不贅述,默認你已經有一個單機的 prometheus在運行,能夠是 pod 也能夠是主機部署,取決於你的運行環境,咱們是在 k8s 集羣外,所以是主機部署。prometheus採集的是地域A的監控數據。你的 prometheus配置能夠是:

啓動配置:

"./prometheus
--config.file=prometheus.yml \
--log.level=info \
--storage.tsdb.path=data/prometheus \
--web.listen-address='0.0.0.0:9090' \
--storage.tsdb.max-block-duration=2h \
--storage.tsdb.min-block-duration=2h \
--storage.tsdb.wal-compression \
--storage.tsdb.retention.time=2h \
--web.enable-lifecycle"

web.enable-lifecycle必定要開,用於熱加載reload你的配置,retention保留 2 小時,prometheus 默認 2 小時會生成一個 block,thanos 會把這個 block 上傳到對象存儲。

採集配置:prometheus.yml

global:
  scrape_interval:     60s
  evaluation_interval: 60s
  external_labels:
     region: 'A'
     replica: 0

rule_files:
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['0.0.0.0:9090']

  - job_name: 'demo-scrape'
    metrics_path: '/metrics'
    params:
    ...

這裏須要聲明external_labels,標註你的地域。若是你是多副本運行,須要聲明你的副本標識,如 0號,1,2 三個副本採集如出一轍的數據,另外2個 prometheus就能夠同時運行,只是replica值不一樣而已。這裏的配置和官方的 federation差很少。

對 prometheus 的要求:

  • 2.2.1版本以上
  • 聲明你的external_labels
  • 啓用--web.enable-admin-api
  • 啓用--web.enable-lifecycle

第 2 步:部署 sidecar 組件

關鍵的步驟來了,最核心莫過於 sidecar組件。sidecar是 k8s 中的一種模式

Sidecar 組件做爲 Prometheus server pod 的 sidecar 容器,與 Prometheus server 部署於同一個 pod 中。 他有兩個做用:

  1. 它使用Prometheus的remote read API,實現了Thanos的Store API。這使後面要介紹的Query 組件能夠將Prometheus服務器視爲時間序列數據的另外一個來源,而無需直接與Prometheus API交互(這就是 sidecar 的攔截做用)
  2. 可選配置:在Prometheus每2小時生成一次TSDB塊時,Sidecar將TSDB塊上載到對象存儲桶中。這使得Prometheus服務器能夠以較低的保留時間運行,同時使歷史數據持久且可經過對象存儲查詢。

固然,這不意味着Prometheus能夠是徹底無狀態的,由於若是它崩潰並從新啓動,您將丟失2個小時的指標,不過若是你的 prometheus 也是多副本,能夠減小這2h 數據的風險。

sidecar配置:

./thanos sidecar \
--prometheus.url="http://localhost:8090" \
--objstore.config-file=./conf/bos.yaml \
--tsdb.path=/home/work/opdir/monitor/prometheus/data/prometheus/
"

配置很簡單,只須要聲明prometheus.url和數據地址便可。objstore.config-file是可選項。若是你要把數據存放在對象存儲(這也是推薦作法),就配置下對象存儲的帳號信息。

thanos 默認支持谷歌雲/AWS等,以 谷歌云爲例,配置以下:

type: GCS
config:
  bucket: ""
  service_account: ""

由於thanos默認還不支持咱們的雲存儲,所以咱們在 thanos代碼中加入了相應的實現,並向官方提交了 pr。

須要注意的是:別忘了爲你的另外兩個副本 1號 和 2號prometheus都搭配一個 sidecar。若是是 pod運行能夠加一個 container,127 訪問,若是是主機部署,指定prometheus端口就行。

另外 sidecar是無狀態的,也能夠多副本,多個 sidecar 能夠訪問一份 prometheus 數據,保證 sidecar自己的拓展性,不過若是是 pod 運行也就沒有這個必要了,sidecar和prometheus 同生共死就好了。

sidecar 會讀取prometheus 每一個 block 中的 meta.json信息,而後擴展這個 json 文件,加入了 Thanos所特有的 metadata 信息。然後上傳到塊存儲上。上傳後寫入thanos.shipper.json 中

第 3 步:部署 query 組件

sidecar 部署完成了,也有了 3 個同樣的數據副本,這個時候若是想直接展現數據,能夠安裝 query 組件

Query組件(也稱爲「查詢」)實現了Prometheus 的HTTP v1 API,能夠像 prometheus 的 graph同樣,經過PromQL查詢Thanos集羣中的數據。

簡而言之,sidecar暴露了StoreAPI,Query從多個StoreAPI中收集數據,查詢並返回結果。Query是徹底無狀態的,能夠水平擴展。

配置:

"
./thanos query \
--http-address="0.0.0.0:8090" \
--store=relica0:10901 \
--store=relica1:10901 \
--store=relica2:10901 \
--store=127.0.0.1:19914 \
"

store 參數表明的就是剛剛啓動的 sidecar 組件,啓動了 3 份,就能夠配置三個relica0、relica一、relica2,10901 是 sidecar 的默認端口。

http-address 表明 query 組件自己的端口,由於他是個 web 服務,啓動後,頁面是這樣的:

和 prometheus 幾乎同樣對吧,有了這個頁面你就不須要關心最初的 prometheus 了,能夠放在這裏查詢。

點擊 store,能夠看到對接了哪些 sidecar。

query 頁面有兩個勾選框,含義是:

  • deduplication:是否去重。默認勾選表明去重,一樣的數據只會出現一條,不然 replica0 和 一、2 徹底相同的數據會查出來 3 條。
  • partial response:是否容許部分響應,默認容許,這裏有一致性的折中,好比 0、一、2 三副本有一個掛掉或者超時了,查詢時就會有一個沒有響應,若是容許返回用戶剩下的 2 份,數據就沒有很強的一致性,但由於一個超時就徹底不返回,就丟掉了可用性,所以默認容許部分響應。

第 4 步:部署 store gateway 組件

你可能注意到了,在第 3 步裏,./thanos query有一條--store是 xxx:19914,並非一直提到的 3 副本,這個 19914 就是接下來要說的store gateway組件。

在第 2 步的 sidecar 配置中,若是你配置了對象存儲objstore.config-file,你的數據就會定時上傳到bucket 中,本地只留 2 小時,那麼要想查詢 2 小時前的數據怎麼辦呢?數據不被 prometheus 控制了,應該如何從 bucket 中拿回來,並提供如出一轍的查詢呢?

Store gateway 組件:Store gateway 主要與對象存儲交互,從對象存儲獲取已經持久化的數據。與sidecar同樣,Store gateway也實現了store api,query 組能夠從 store gateway 查詢歷史數據。

配置以下:

./thanos store \
--data-dir=./thanos-store-gateway/tmp/store \
--objstore.config-file=./thanos-store-gateway/conf/bos.yaml \
--http-address=0.0.0.0:19904 \
--grpc-address=0.0.0.0:19914 \
--index-cache-size=250MB \
--sync-block-duration=5m \
--min-time=-2w \
--max-time=-1h \

grpc-address就是store api暴露的端口,也就是query 中--store是 xxx:19914的配置。

由於Store gateway須要從網絡上拉取大量歷史數據加載到內存,所以會大量消耗 cpu 和內存,這個組件也是 thanos 面世時被質疑過的組件,不過當前的性能還算能夠,遇到的一些問題後面會提到。

Store gateway也能夠無限拓展,拉取同一份 bucket 數據。

放個示意圖,一個 thanos 副本,掛了多個地域的 store 組件

到這裏,thanos 的基本使用就結束了,至於 compact 壓縮和 bucket 校驗,不是核心功能,compact咱們只是簡單部署了一下,rule組件咱們沒有使用,就不作介紹了。

5.查看數據

有了多地域多副本的數據,就能夠結合 grafana 作全局視圖了,好比:

按地域和集羣查看 etcd 的性能指標:

按地域、集羣、機器查看核心組件監控,如多副本 master 機器上的各類性能

數據聚合在一塊兒以後,能夠將全部視圖都集中展現,好比還有這些面板:

  • 機器監控:node-exporter、process-exporter
  • pod 資源使用: cadvisor
  • docker、kube-proxy、kubelet 監控
  • scheduler、controller-manager、etcd、apiserver 監控
  • kube-state-metrics 元信息
  • k8s events
  • mtail 等日誌監控

Receive 模式

前面提到的全部組件都是基於 sidecar 模式配置的,但thanos還有一種Receive模式,不太經常使用,只是在Proposals中出現

由於一些網絡限制,咱們以前嘗試過Receive方案,這裏能夠描述下Receive的使用場景:

  1. sidecar 模式有一個缺點:就是2 小時內的數據仍然須要經過 sidecar->prometheus來獲取,也就是仍然依賴 prometheus,並非徹底的數據在外部存儲。若是你的網絡只容許你查詢特定的存儲數據,沒法達到集羣內的prometheus,那這 2 小時的數據就丟失了,而 Receive模式採用了remote write 就沒有所謂的 2 小時 block 的問題了。
  2. sidecar 模式對網絡連通性是有要求的,若是你是多租戶環境或者是雲廠商,對象存儲(歷史數據)query 組件通常在控制面,方便作權限校驗和接口服務封裝,而 sidecar 和 prometheus卻在集羣內,也就是用戶側。控制面和用戶側的網絡有時候會有限制,是不通的,這個時候會有一些限制致使你沒法使用 sidecar
  3. 租戶和控制面隔離,和第2 條相似,但願數據徹底存在控制面,我一直以爲Receive就是爲了雲廠商服務的。。

不過Receive畢竟不是默認方案,若是不是特別須要,仍是用默認的 sidecar 爲好

一些問題

prometheus 壓縮

壓縮:官方文檔有提到,使用sidecar時,須要將 prometheus 的--storage.tsdb.min-block-duration 和 --storage.tsdb.max-block-duration,這兩個值設置爲2h,兩個參數相等才能保證prometheus關閉了本地壓縮,其實這兩個參數在 prometheus -help 中並無體現,prometheus 做者也說明這只是爲了開發測試才用的參數,不建議用戶修改。而 thanos 要求關閉壓縮是由於 prometheus 默認會以2,25,25*5的週期進行壓縮,若是不關閉,可能會致使 thanos 剛要上傳一個 block,這個 block 卻被壓縮中,致使上傳失敗。

不過你也沒必要擔憂,由於在 sidecar 啓動時,會堅持這兩個參數,若是不合適,sidecar會啓動失敗
43a131c689d9fedba5a7844363876ee7

store-gateway

store-gateway: store 組件資源消耗是最大的,畢竟他要拉取遠程數據,並加載到本地供查詢,若是你想控制歷史數據和緩存週期,能夠修改相應的配置,如

--index-cache-size=250MB \
--sync-block-duration=5m \ 
--min-time=-2w \ 最大查詢 1 周
--max-time=-1h \

store-gateway 默認支持索引緩存,來加快tsdb 塊的查找速度,但有時候啓動會佔用了大量的內存,在 0.11.0以後的版本作了修復,能夠查看這個issue

Prometheus 2.0 已經對存儲層進行了優化。例如按照時間和指標名字,連續的儘可能放在一塊兒。而 store gateway能夠獲取存儲文件的結構,所以能夠很好的將指標存儲的請求翻譯爲最少的 object storage 請求。對於那種大查詢,一次能夠拿成百上千個 chunks 數據。

二在 store 的本地,只有 index 數據是放入 cache的,chunk 數據雖然也能夠,可是就要大幾個數量級了。目前,從對象存儲獲取 chunk 數據只有很小的延時,所以也沒什麼動力去將 chunk 數據給 cache起來,畢竟這個對資源的需求很大。

store-gateway中的數據:

每一個文件夾中實際上是一個個的索引文件index.cache.json

compactor組件

prometheus數據愈來愈多,查詢必定會愈來愈慢,thanos提供了一個compactor組件來處理,他有兩個功能,

  • 一個是作壓縮,就是把舊的數據不斷的合併。
  • 另一個是降採樣,他會把存儲的數據,按照必定的時間,算出最大,最小等值,會根據查詢的間隔,進行控制,返回採樣的數據,而不是真實的點,在查詢特別長的時間的數據的時候,看的主要是趨勢,精度是能夠選擇降低的。
  • 注意的是compactor並不會減小磁盤佔用,反而會增長磁盤佔用(作了更高維度的聚合)。

經過以上的方式,有效了優化查詢,可是並非萬能的。由於業務數據總在增加,這時候可能要考慮業務拆分了,咱們須要對業務有必定的估算,例如不一樣的業務存儲在不一樣bucket裏(須要改造或者多部署幾個 sidecar)。例若有5個bucket,再準備5個store gateway進行代理查詢。減小單個 store 數據過大的問題。

第二個方案是時間切片,也就是就是上面提到的store gateway能夠選擇查詢多長時間的數據。支持兩種表達,一種是基於相對時間的,例如--max-time 3d前到5d前的。一種是基於絕對時間的,19年3月1號到19年5月1號。例如想查詢3個月的數據,一個store代理一個月的數據,那麼就須要3個store來合做。

query 的去重

query組件啓動時,默認會根據query.replica-label字段作重複數據的去重,你也能夠在頁面上勾選deduplication 來決定。query 的結果會根據你的query.replica-label的 label選擇副本中的一個進行展現。可若是 0,1,2 三個副本都返回了數據,且值不一樣,query 會選擇哪個展現呢?

thanos會基於打分機制,選擇更爲穩定的 replica 數據, 具體邏輯在:https://github.com/thanos-io/...

參考

本文爲容器監控實踐系列文章,完整內容見:container-monitor-book

相關文章
相關標籤/搜索