天天看點

一文詳解 Prometheus 的高可用方案:Thanos

一文詳解 Prometheus 的高可用方案:Thanos

背景

在高可用 prometheus:問題集錦文章中有簡單提到 Prometheus 的高可用方案,嘗試了聯邦、Remote Write 之後,我們最終選擇了 Thanos 作為監控配套元件,利用其全局視圖來管理我們的多地域、300+叢集的監控資料。本文主要介紹 Thanos 的一些元件使用和心得體會。

Prometheus 官方的高可用有幾種方案:

  1. HA:即兩套 Prometheus 采集完全一樣的資料,外邊挂負載均衡
  2. HA + 遠端存儲:除了基礎的多副本 Prometheus,還通過 Remote write 寫入到遠端存儲,解決存儲持久化問題
  3. 聯邦叢集:即 Federation,按照功能進行分區,不同的 Shard 采集不同的資料,由 Global 節點來統一存放,解決監控資料規模的問題。

使用官方建議的多副本 + 聯邦仍然會遇到一些問題,本質原因是 Prometheus 的本地存儲沒有資料同步能力,要在保證可用性的前提下再保持資料一緻性是比較困難的,基本的多副本 Proxy 滿足不了要求,比如:

  • Prometheus 叢集的後端有 A 和 B 兩個執行個體,A 和 B 之間沒有資料同步。A 當機一段時間,丢失了一部分資料,如果負載均衡正常輪詢,請求打到A 上時,資料就會異常。
  • 如果 A 和 B 的啟動時間不同,時鐘不同,那麼采集同樣的資料時間戳也不同,就多副本的資料不相同。就算用了遠端存儲,A 和 B 不能推送到同一個 TSDB,如果每人推送自己的 TSDB,資料查詢走哪邊就是問題
  • 官方建議資料做 Shard,然後通過 Federation 來實作高可用,但是邊緣節點和 Global 節點依然是單點,需要自行決定是否每一層都要使用雙節點重複采集進行保活。也就是仍然會有單機瓶頸。
  • 另外部分敏感報警盡量不要通過 Global 節點觸發,畢竟從 Shard 節點到 Global 節點傳輸鍊路的穩定性會影響資料到達的效率,進而導緻報警實效降低。

目前大多數的 Prometheus 的叢集方案是在存儲、查詢兩個角度上保證資料的一緻:

  • 存儲角度:如果使用 Remote Write 遠端存儲, A 和 B 後面可以都加一個 Adapter,Adapter 做選主邏輯,隻有一份資料能推送到 TSDB,這樣可以保證一個異常,另一個也能推送成功,資料不丢,同時遠端存儲隻有一份,是共享資料。方案可以參考這篇文章
  • 存儲角度:仍然使用 Remote Write 遠端存儲,但是 A 和 B 分别寫入 TSDB1 和 TSDB2 兩個時序資料庫,利用 Sync 的方式在 TSDB1 和 TSDB2 之間做資料同步,保證資料是全量的。
  • 查詢角度:上邊的方案需要自己實作,有侵入性且有一定風險,是以大多數開源方案是在查詢層面做文章,比如 Thanos 或者 Victoriametrics,仍然是兩份資料,但是查詢時做資料去重和 join。隻是 Thanos是通過 Sidecar 把資料放在對象存儲,Victoriametrics 是把資料 Remote Write 到自己的 Server 執行個體,但查詢層 Thanos Query 和 Victor的 Promxy 的邏輯基本一緻,都是為全局視圖服務

實際需求

随着我們的叢集規模越來越大,監控資料的種類和數量也越來越多:如Master/Node 機器監控、程序監控、4 大核心元件的性能監控,POD 資源監控、kube-stats-metrics、K8S events監控、插件監控等等。除了解決上面的高可用問題,我們還希望基于 Prometheus 建構全局視圖,主要需求有:

  • 長期存儲: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/StackDriver..)和商業産品之後,我們選擇了 Thanos,準确的說 Thanos 隻是監控套件,與原生 Prometheus 結合,滿足了長期存儲 + 無限拓展 + 全局視圖 + 無侵入性的需求。

Thanos 架構

Thanos 的預設模式:sidecar 方式

一文詳解 Prometheus 的高可用方案:Thanos

除了 這個 sidecar 方式,Thanos 還有一種不太常用的 receive 模式,後面會提到。

Thanos 是一組元件,在官網上可以看到包括:

  • 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 中。他有兩個作用:

  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: GCSconfig:  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、relica1、relica2,10901 是 sidecar 的預設端口。

http-address 代表 query 元件本身的端口,因為他是個 web 服務,啟動後,頁面是這樣的:

一文詳解 Prometheus 的高可用方案:Thanos

和 Prometheus 幾乎一樣對吧,有了這個頁面你就不需要關心最初的 Prometheus 了,可以放在這裡查詢。

點選 store,可以看到對接了哪些 sidecar。

一文詳解 Prometheus 的高可用方案:Thanos

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

  • deduplication:是否去重。預設勾選代表去重,同樣的資料隻會出現一條,否則 replica0 和 1、2 完全相同的資料會查出來 3 條。
  • partial response:是否允許部分響應,預設允許,這裡有一緻性的折中,比如 0、1、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 元件

一文詳解 Prometheus 的高可用方案:Thanos

其中一個地域的資料統計:

查詢一個月曆史資料速度還可以,主要是資料持久化沒有運維壓力,随意擴充,成本低。

一文詳解 Prometheus 的高可用方案:Thanos

到這裡,Thanos 的基本使用就結束了,至于 compact 壓縮和 bucket 校驗,不是核心功能,compact的資源消耗也特别大,rule元件我們沒有使用,就不做介紹了。

第5步:檢視資料

有了多地域多副本的資料,就可以結合 Grafana 做全局視圖了,比如:

按地域和叢集檢視 ETCD 的性能名額:

一文詳解 Prometheus 的高可用方案:Thanos

按地域、叢集、機器檢視核心元件監控,如多副本 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中出現

一文詳解 Prometheus 的高可用方案:Thanos

因為一些網絡限制,我們之前嘗試過 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會啟動失敗

一文詳解 Prometheus 的高可用方案:Thanos

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中的資料:

一文詳解 Prometheus 的高可用方案:Thanos

每個檔案夾中其實是一個個的索引檔案 index.cache.json

compactor元件

Prometheus 資料越來越多,查詢一定會越來越慢,Thanos 提供了一個 compactor 元件來處理,他有兩個功能,

  • 一個是做壓縮,就是把舊的資料不斷的合并。
  • 一個是降采樣,他會把存儲的資料,按照一定的時間,算出最大,最小等值,會根據查詢的間隔,進行控制,傳回采樣的資料,而不是真實的點,在查詢特别長的時間的資料的時候,看的主要是趨勢,精度是可以選擇下降的。
  • 注意的是 Compactor 并不會減少磁盤占用,反而會增加磁盤占用(做了更高次元的聚合)。

thanos 元件的優化并不是萬能的,因為業務資料總在增長,這時候可能要考慮業務拆分了。我們需要對業務有一定的劃分,不同的業務監控放在不同bucket裡(需要改造或者多部署幾個 sidecar)。例如有5個 bucket ,再準備5個 store gateway 進行代理查詢。減少單個 store 資料過大的問題。

第二個方案是時間切片,也就是上面提到的 store gateway,可以選擇查詢多長時間的資料。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/thanos/blob/55cb8ca38b3539381dc6a781e637df15c694e50a/pkg/query/iter.go

參考

  • https://thanos.io/
  • https://www.percona.com/blog/2018/09/20/Prometheus-2-times-series-storage-performance-analyses/
  • https://qianyongchao.blog/2019/01/03/Prometheus-thanos-design-%E4%BB%8B%E7%BB%8D/
  • https://github.com/thanos-io/thanos/issues/405
  • https://katacoda.com/bwplotka/courses/thanos
  • https://medium.com/faun/comparing-thanos-to-victoriametrics-cluster-b193bea1683
  • https://www.youtube.com/watch?v=qQN0N14HXPM
一文詳解 Prometheus 的高可用方案:Thanos