備份并查看一段時(shí)間的 Prometheus 數(shù)據(jù)

在 TiDB 里面,我們使用 Prometheus 作為我們 Monitor 工具,然后使用 Grafana 展示,這套解決方案應(yīng)該是現(xiàn)在非常流行的,功能也很強(qiáng)大,很多問題,我們不需要登錄到問題機(jī)器,直接看 metric 就能夠定位。一切都很美好,直到我們發(fā)現(xiàn)了一個(gè)嚴(yán)重的問題 - 有些用戶,只有內(nèi)網(wǎng)環(huán)境,我們看不到監(jiān)控。。。

因?yàn)槲覀儧]法看到監(jiān)控,所以如果用戶那邊出現(xiàn)了問題,就會(huì)非常的麻煩,通常我們會(huì)使用 TeamViewer,但 TeamViewer 有幾個(gè)問題,一個(gè)就是網(wǎng)速有時(shí)候會(huì)很慢,操作幾次之后,大家都會(huì)崩潰的。另外就是客戶不能用這臺(tái)機(jī)器干事情了,有時(shí)候他們不愿意。

另一種方案,就是使用微信,然后直接指導(dǎo)用戶,『 麻煩幫我把這個(gè) metric 給截圖一下,麻煩再給那個(gè) metric 給截圖下』不用說,讓用戶這么干幾次,如果我是用戶,我也會(huì)發(fā)飆了。

所以我們需要有一套機(jī)制,能非常好的幫我們自動(dòng)收集所有的 metrics。

PDF Exporter

最開始,我們使用的是直接將 Grafana 上面的面板按照 PDF 格式直接導(dǎo)出,譬如使用 Reporter,不過這個(gè)庫(kù)需要安裝 pdflatex,但這在用戶那邊是不可能的,所以我們稍微做了改進(jìn),用了 gopdf 來生成 PDF,大概樣子類似這樣:

使用這種方式雖然能快速的生成 metrics 的 PDF,但有一個(gè)問題就是展示的 metrics 是靜態(tài)的,我們不能用選擇某一個(gè)曲線進(jìn)行高亮展示,或者是重新選擇一段區(qū)間進(jìn)行更細(xì)化的展示。

為了解決這個(gè)問題,我們其實(shí)需要考慮的是將 Prometheus 的數(shù)據(jù)給拿出來,重新導(dǎo)入到我們本地的 Prometheus 里面,然后用 Grafana 展示。Prometheus 提供了 snapshot 的功能,能支持將 Prometheus 的數(shù)據(jù)給 dump 出來,但這個(gè)功能會(huì) dump 所有的 Prometheus 數(shù)據(jù),而我們的數(shù)據(jù)通常都至少保留 15 天,所以這個(gè) dump 出來的數(shù)據(jù)實(shí)在是太大了,根本不可能這么做。

Remote Storage

對(duì)于我們來說,其實(shí)是不需要 dump 出來 Prometheus 所有的數(shù)據(jù)的。因?yàn)槲覀冎恍枰桥挪殄e(cuò)誤,通常只會(huì)關(guān)心一段時(shí)間的 metrics 變化,所以只需要將那一段時(shí)間的 metrics 數(shù)據(jù)給弄出來就可以了,而且因?yàn)闀r(shí)間不會(huì)很長(zhǎng),數(shù)據(jù)量不會(huì)特別大。但不幸的是,Prometheus 并不提供這樣的機(jī)制。

雖然 Prometheus 不提供,但不代表我們不能做。Prometheus 提供了一套 Remote Storage API,能讓 Prometheus 對(duì) remote storage 進(jìn)行讀寫,參考官網(wǎng):

image

所以我們可以基于 Remote Storage 來做。簡(jiǎn)單的架構(gòu)圖如下

+------------------+  write   +---------------+  dump   +-----------+
| User Prometheus  | -------> | Write Storage | ------> | Dump Data |
+------------------+          +---------------+         +-----------+
                                                          |
                                                          |
                                                          |
                                                          |
+------------------+  read    +---------------+  load     |
| Local Prometheus | -------> | Read Storage  | <---------+
+------------------+          +---------------+           

流程就比較簡(jiǎn)單了:

  1. 用戶的 Prometheus 將 metrics 數(shù)據(jù)寫入到 Write Storage
  2. Write Storage 支持按照某一段時(shí)間區(qū)間將相應(yīng)的 metrics 給 dump 出來
  3. 拿到 dump 的數(shù)據(jù)之后,我們可以導(dǎo)入到本地的 Read Storage
  4. 啟動(dòng)本地的 Prometheus,讓它從 Read Storage 讀取數(shù)據(jù)

實(shí)現(xiàn)

可以看到,通過 Remote Storage,我們能方便的實(shí)現(xiàn) Prometheus 一段時(shí)間數(shù)據(jù) dump + load 的工作,而對(duì)于實(shí)現(xiàn)來說,無非就是幾個(gè)地方需要考量:

  1. 如何與 Prometheus 交互,這個(gè)其實(shí)就是實(shí)現(xiàn) Remote Storage Protocol,這方面,Prometheus 有太多的例子,譬如官方的,這里就不說明了。
  2. 如何在自己的 Storage 里面存儲(chǔ)數(shù)據(jù),并進(jìn)行高效的檢索。這里我們重點(diǎn)說明下這個(gè)。

因?yàn)槲覀冏罡哳l的需求是按照某一段時(shí)間從 Write Storage 里面 dump 出來數(shù)據(jù),而 Prometheus 從 Read Storage 里面讀取數(shù)據(jù)的時(shí)候也是按照時(shí)間區(qū)間來的,所以對(duì)于我們的 Storage 來說,我們僅僅需要一個(gè)高性能的 KV 數(shù)據(jù)庫(kù)就可以了。這里,為了簡(jiǎn)單實(shí)現(xiàn),我選擇了 badger。其實(shí) boltdb,LMDB,LevelD 都可以。

Prometheus 給 Remote Storage 寫入數(shù)據(jù)的時(shí)候,會(huì)發(fā)送如下的數(shù)據(jù)結(jié)構(gòu):

message Sample {
  double value    = 1;
  int64 timestamp = 2;
}

message TimeSeries {
  repeated Label labels   = 1;
  repeated Sample samples = 2;
}

message Label {
  string name  = 1;
  string value = 2;
}

message Labels {
  repeated Label labels = 1 [(gogoproto.nullable) = false];
}

每一個(gè) TimeSeries,會(huì)有多個(gè) Sample,每個(gè) Sample 會(huì)帶上一個(gè)毫秒精度的 timestamp 以及 value,所有的 sample 會(huì)共享一個(gè) label 集合,這個(gè) label 集合里面,我們可以通過 __name__ 字段拿到這個(gè) metric 實(shí)際的名字。對(duì)于我們來說,所有的查詢都會(huì)帶上 metric name,所以我們 KV 里面,key 的格式如下:

|timestamp|counter|name| 

這里額外加了一個(gè) counter,可以認(rèn)為是一個(gè)全局的唯一 ID,主要是為了防止 timestamp 和 name 不唯一的情況。Timestamp 和 counter 都按照大端序排序,這樣就能保證我們所有的 metrics 能按照時(shí)間先后順序在 KV 里面存儲(chǔ)了。獲取某一段時(shí)間的 metric,只需要靠著底層 engine 自帶的 seek 功能就可以了,譬如對(duì)于后面的查詢來說,流程如下:

  • 根據(jù) timestamp 區(qū)間,seek 到 start key,然后依次遍歷,直到遇到時(shí)間戳超過區(qū)間的數(shù)據(jù)
  • 每次獲取一個(gè) key,判斷 name 是否一致
  • 如果是需要查詢的 metric,讀取數(shù)據(jù),判斷 label 是否匹配查詢條件
  • 如果所有條件匹配,拿到 metric 的值,返回給 Prometheus

例子

我寫了一個(gè)簡(jiǎn)單的程序,prom-porter 來驗(yàn)證我的想法,使用很簡(jiǎn)單,編譯好 write 和 read storage,在用戶的 Prometheus 那邊加上 Write Storage 的地址:

remote_write:
  - url: "http://localhost:1234/write"

啟動(dòng)之后,Prometheus 就會(huì)將自己的 metrics 給寫入到 Write Storage,然后我們將 一段時(shí)間數(shù)據(jù) dump 出來

curl http://localhost:1234/dump?start=timestamp_ms&end=timestamp_ms

將得到的數(shù)據(jù)用 Read Storage 載入啟動(dòng),同時(shí)在我們自己的 Prometheus 配置上 Read Storage 地址:

remote_read:
  - url: "http://localhost:1235/read"

然后我們就可以在 Grafana 上面指定好我們自己的 Prometheus,進(jìn)行查詢了,下圖就是一個(gè)簡(jiǎn)單的 PD 面板,可以看到,數(shù)據(jù)都能正常的顯示出來,不過因?yàn)橹挥幸欢螘r(shí)間的數(shù)據(jù),所以超過這段時(shí)間的范圍了,就不能查詢了。

小結(jié)

上面只是我的一個(gè)簡(jiǎn)單嘗試,如果有更好的辦法,歡迎聯(lián)系我,我的郵箱 tl@pingcap.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容