在 TiDB 里面,我們使用 Prometheus 作為我們 Monitor 工具晦溪,然后使用 Grafana 展示,這套解決方案應(yīng)該是現(xiàn)在非常流行的台汇,功能也很強(qiáng)大亭姥,很多問題稼钩,我們不需要登錄到問題機(jī)器,直接看 metric 就能夠定位达罗。一切都很美好坝撑,直到我們發(fā)現(xiàn)了一個嚴(yán)重的問題 - 有些用戶,只有內(nèi)網(wǎng)環(huán)境粮揉,我們看不到監(jiān)控巡李。。扶认。
因為我們沒法看到監(jiān)控击儡,所以如果用戶那邊出現(xiàn)了問題,就會非常的麻煩蝠引,通常我們會使用 TeamViewer,但 TeamViewer 有幾個問題蛀柴,一個就是網(wǎng)速有時候會很慢螃概,操作幾次之后,大家都會崩潰的鸽疾。另外就是客戶不能用這臺機(jī)器干事情了吊洼,有時候他們不愿意。
另一種方案制肮,就是使用微信冒窍,然后直接指導(dǎo)用戶,『 麻煩幫我把這個 metric 給截圖一下豺鼻,麻煩再給那個 metric 給截圖下』不用說综液,讓用戶這么干幾次,如果我是用戶儒飒,我也會發(fā)飆了谬莹。
所以我們需要有一套機(jī)制,能非常好的幫我們自動收集所有的 metrics。
PDF Exporter
最開始附帽,我們使用的是直接將 Grafana 上面的面板按照 PDF 格式直接導(dǎo)出埠戳,譬如使用 Reporter,不過這個庫需要安裝 pdflatex蕉扮,但這在用戶那邊是不可能的整胃,所以我們稍微做了改進(jìn),用了 gopdf 來生成 PDF喳钟,大概樣子類似這樣:
使用這種方式雖然能快速的生成 metrics 的 PDF屁使,但有一個問題就是展示的 metrics 是靜態(tài)的,我們不能用選擇某一個曲線進(jìn)行高亮展示荚藻,或者是重新選擇一段區(qū)間進(jìn)行更細(xì)化的展示屋灌。
為了解決這個問題,我們其實需要考慮的是將 Prometheus 的數(shù)據(jù)給拿出來应狱,重新導(dǎo)入到我們本地的 Prometheus 里面共郭,然后用 Grafana 展示。Prometheus 提供了 snapshot 的功能疾呻,能支持將 Prometheus 的數(shù)據(jù)給 dump 出來除嘹,但這個功能會 dump 所有的 Prometheus 數(shù)據(jù),而我們的數(shù)據(jù)通常都至少保留 15 天岸蜗,所以這個 dump 出來的數(shù)據(jù)實在是太大了尉咕,根本不可能這么做。
Remote Storage
對于我們來說璃岳,其實是不需要 dump 出來 Prometheus 所有的數(shù)據(jù)的年缎。因為我們只需要是排查錯誤,通常只會關(guān)心一段時間的 metrics 變化铃慷,所以只需要將那一段時間的 metrics 數(shù)據(jù)給弄出來就可以了单芜,而且因為時間不會很長,數(shù)據(jù)量不會特別大犁柜。但不幸的是洲鸠,Prometheus 并不提供這樣的機(jī)制。
雖然 Prometheus 不提供馋缅,但不代表我們不能做扒腕。Prometheus 提供了一套 Remote Storage API,能讓 Prometheus 對 remote storage 進(jìn)行讀寫萤悴,參考官網(wǎng):
所以我們可以基于 Remote Storage 來做瘾腰。簡單的架構(gòu)圖如下
+------------------+ write +---------------+ dump +-----------+
| User Prometheus | -------> | Write Storage | ------> | Dump Data |
+------------------+ +---------------+ +-----------+
|
|
|
|
+------------------+ read +---------------+ load |
| Local Prometheus | -------> | Read Storage | <---------+
+------------------+ +---------------+
流程就比較簡單了:
- 用戶的 Prometheus 將 metrics 數(shù)據(jù)寫入到 Write Storage
- Write Storage 支持按照某一段時間區(qū)間將相應(yīng)的 metrics 給 dump 出來
- 拿到 dump 的數(shù)據(jù)之后,我們可以導(dǎo)入到本地的 Read Storage
- 啟動本地的 Prometheus稚疹,讓它從 Read Storage 讀取數(shù)據(jù)
實現(xiàn)
可以看到居灯,通過 Remote Storage祭务,我們能方便的實現(xiàn) Prometheus 一段時間數(shù)據(jù) dump + load 的工作,而對于實現(xiàn)來說怪嫌,無非就是幾個地方需要考量:
- 如何與 Prometheus 交互义锥,這個其實就是實現(xiàn) Remote Storage Protocol,這方面岩灭,Prometheus 有太多的例子拌倍,譬如官方的,這里就不說明了噪径。
- 如何在自己的 Storage 里面存儲數(shù)據(jù)柱恤,并進(jìn)行高效的檢索。這里我們重點說明下這個找爱。
因為我們最高頻的需求是按照某一段時間從 Write Storage 里面 dump 出來數(shù)據(jù)梗顺,而 Prometheus 從 Read Storage 里面讀取數(shù)據(jù)的時候也是按照時間區(qū)間來的,所以對于我們的 Storage 來說车摄,我們僅僅需要一個高性能的 KV 數(shù)據(jù)庫就可以了寺谤。這里,為了簡單實現(xiàn)吮播,我選擇了 badger变屁。其實 boltdb,LMDB意狠,LevelD 都可以粟关。
Prometheus 給 Remote Storage 寫入數(shù)據(jù)的時候,會發(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];
}
每一個 TimeSeries环戈,會有多個 Sample闷板,每個 Sample 會帶上一個毫秒精度的 timestamp 以及 value,所有的 sample 會共享一個 label 集合院塞,這個 label 集合里面蛔垢,我們可以通過 __name__
字段拿到這個 metric 實際的名字。對于我們來說迫悠,所有的查詢都會帶上 metric name,所以我們 KV 里面巩梢,key 的格式如下:
|timestamp|counter|name|
這里額外加了一個 counter创泄,可以認(rèn)為是一個全局的唯一 ID,主要是為了防止 timestamp 和 name 不唯一的情況括蝠。Timestamp 和 counter 都按照大端序排序鞠抑,這樣就能保證我們所有的 metrics 能按照時間先后順序在 KV 里面存儲了。獲取某一段時間的 metric忌警,只需要靠著底層 engine 自帶的 seek 功能就可以了搁拙,譬如對于后面的查詢來說秒梳,流程如下:
- 根據(jù) timestamp 區(qū)間,seek 到 start key箕速,然后依次遍歷酪碘,直到遇到時間戳超過區(qū)間的數(shù)據(jù)
- 每次獲取一個 key,判斷 name 是否一致
- 如果是需要查詢的 metric盐茎,讀取數(shù)據(jù)兴垦,判斷 label 是否匹配查詢條件
- 如果所有條件匹配,拿到 metric 的值字柠,返回給 Prometheus
例子
我寫了一個簡單的程序探越,prom-porter 來驗證我的想法,使用很簡單窑业,編譯好 write 和 read storage钦幔,在用戶的 Prometheus 那邊加上 Write Storage 的地址:
remote_write:
- url: "http://localhost:1234/write"
啟動之后,Prometheus 就會將自己的 metrics 給寫入到 Write Storage常柄,然后我們將 一段時間數(shù)據(jù) dump 出來
curl http://localhost:1234/dump?start=timestamp_ms&end=timestamp_ms
將得到的數(shù)據(jù)用 Read Storage 載入啟動鲤氢,同時在我們自己的 Prometheus 配置上 Read Storage 地址:
remote_read:
- url: "http://localhost:1235/read"
然后我們就可以在 Grafana 上面指定好我們自己的 Prometheus,進(jìn)行查詢了拐纱,下圖就是一個簡單的 PD 面板铜异,可以看到,數(shù)據(jù)都能正常的顯示出來秸架,不過因為只有一段時間的數(shù)據(jù)揍庄,所以超過這段時間的范圍了,就不能查詢了东抹。
小結(jié)
上面只是我的一個簡單嘗試蚂子,如果有更好的辦法,歡迎聯(lián)系我缭黔,我的郵箱 tl@pingcap.com