Prometheus提供了本地存儲,即tsdb時序數據庫,本地存儲給Prometheus帶來了簡單高效的使用體驗,prometheus2.0之後壓縮數據能力也獲得了很大的提高。能夠在單節點的狀況下知足大部分用戶的監控需求。html
但本地存儲也限制了Prometheus的可擴展性,帶來了數據持久化等一系列的問題。爲了解決單節點存儲的限制,prometheus沒有本身實現集羣存儲,而是提供了遠程讀寫的接口,讓用戶本身選擇合適的時序數據庫來實現prometheus的擴展性。linux
Prometheus 1.x版本的TSDB(V2存儲引擎)基於LevelDB,而且使用了和Facebook Gorilla同樣的壓縮算法,可以將16個字節的數據點壓縮到平均1.37個字節。git
Prometheus 2.x版本引入了全新的V3存儲引擎,提供了更高的寫入和查詢性能算法
如下全部內容均基於prometheus2.7版本sql
Prometheus按2小時一個block進行存儲,每一個block由一個目錄組成,該目錄裏包含:一個或者多個chunk文件(保存timeseries數據)、一個metadata文件、一個index文件(經過metric name和labels查找timeseries數據在chunk文件的位置)。數據庫
最新寫入的數據保存在內存block中,達到2小時後寫入磁盤。爲了防止程序崩潰致使數據丟失,實現了WAL(write-ahead-log)機制,啓動時會以寫入日誌(WAL)的方式來實現重播,從而恢復數據。json
刪除數據時,刪除條目會記錄在獨立的tombstone文件中,而不是當即從chunk文件刪除。緩存
經過時間窗口的形式保存全部的樣本數據,能夠明顯提升Prometheus的查詢效率,當查詢一段時間範圍內的全部樣本數據時,只須要簡單的從落在該範圍內的塊中查詢數據便可。bash
這些2小時的block會在後臺壓縮成更大的block,數據壓縮合併成更高level的block文件後刪除低level的block文件。這個和leveldb、rocksdb等LSM樹的思路一致。服務器
這些設計和Gorilla的設計高度類似,因此Prometheus幾乎就是等於一個緩存TSDB。它本地存儲的特色決定了它不能用於long-term數據存儲,只能用於短時間窗口的timeseries數據保存和查詢,而且不具備高可用性(宕機會致使歷史數據沒法讀取)。
內存中的block數據未寫入磁盤時,block目錄下面主要保存wal文件:
./data/01BKGV7JBM69T2G1BGBGM6KB12 ./data/01BKGV7JBM69T2G1BGBGM6KB12/meta.json ./data/01BKGV7JBM69T2G1BGBGM6KB12/wal/000002 ./data/01BKGV7JBM69T2G1BGBGM6KB12/wal/000001
持久化的block目錄下wal文件被刪除,timeseries數據保存在chunk文件裏。index用於索引timeseries在wal文件裏的位置。
./data/01BKGV7JC0RY8A6MACW02A2PJD ./data/01BKGV7JC0RY8A6MACW02A2PJD/meta.json ./data/01BKGV7JC0RY8A6MACW02A2PJD/index ./data/01BKGV7JC0RY8A6MACW02A2PJD/chunks ./data/01BKGV7JC0RY8A6MACW02A2PJD/chunks/000001 ./data/01BKGV7JC0RY8A6MACW02A2PJD/tombstones
對於本地存儲,prometheus提供了一些配置項,主要包括:
Prometheus將全部當前使用的塊保留在內存中。此外,它將最新使用的塊保留在內存中,最大內存能夠經過storage.local.memory-chunks標誌配置。
監測當前使用的內存量:
監測當前使用的存儲指標:
prometheus 2.0於2017-11-08發佈,主要是存儲引擎進行了優化。
性能的總體提升:
在Kubernetes集羣這樣的動態環境中,prometheus的數據平面一般看起來是這種樣式
如:
requests_total{path="/status", method="GET", instance="10.0.0.1:80"} requests_total{path="/status", method="POST", instance="10.0.0.3:80"} requests_total{path="/", method="GET", instance="10.0.0.2:80"}
Prometheus按期爲全部系列收集新數據點,這意味着它必須在時間軸的右端執行垂直寫入。可是,在查詢時,咱們可能但願訪問平面上任意區域的矩形(各類label條件)
所以爲了可以在大量數據中有效地查找查詢序列,咱們須要一個索引。
在Prometheus 1.x存儲層能夠很好地處理垂直寫入模式,可是隨着規模增大,索引或出現一些問題,所以在2.0版本中從新設計了存儲引擎和索引,主要改造是:
樣本壓縮
現有存儲層的樣本壓縮功能在Prometheus的早期版本中發揮了重要做用。單個原始數據點佔用16個字節的存儲空間。但當普羅米修斯每秒收集數十萬個數據點時,能夠快速填滿硬盤。
但,同一系列中的樣本每每很是類似,咱們能夠利用這一類樣品(一樣label)進行有效的壓縮。批量壓縮一系列的許多樣本的塊,在內存中,將每一個數據點壓縮到平均1.37字節的存儲。
這種壓縮方案運行良好,也保留在新版本2存儲層的設計中。具體壓縮算法能夠參考:Facebook的「Gorilla」論文中
時間分片
咱們將新的存儲層劃分爲塊(block),每一個塊在一段時間內保存全部序列。每一個塊充當獨立數據庫。
這樣每次查詢,僅檢查所請求的時間範圍內的塊子集,查詢執行時間天然會減小。
這種佈局也使刪除舊數據變得很是容易(這在1.x的存儲設計中是一個很耗時的操做)。但在2.x中,一旦塊的時間範圍徹底落後於配置的保留邊界,它就能夠徹底丟棄。
索引
通常prometheus的查詢是把metric+label作關鍵字的,並且是很寬泛,徹底用戶自定義的字符,所以沒辦法使用常規的sql數據庫,prometheus的存儲層使用了全文檢索中的倒排索引概念,將每一個時間序列視爲一個小文檔。而metric和label對應的是文檔中的單詞。
例如,requests_total{path="/status", method="GET", instance="10.0.0.1:80"}是包含如下單詞的文檔:
基準測試
cpu、內存、查詢效率都比1.x版本獲得了大幅度的提高
具體測試結果參考:https://dzone.com/articles/pr...
若是您懷疑數據庫中的損壞引發的問題,則能夠經過使用storage.local.dirtyflag配置,來啓動服務器來強制執行崩潰恢復。
若是沒有幫助,或者若是您只想刪除現有的數據庫,能夠經過刪除存儲目錄的內容輕鬆地啓動:
Prometheus默認是本身帶有存儲的,保存的時間爲15天。但本地存儲也意味着Prometheus沒法持久化數據,沒法存儲大量歷史數據,同時也沒法靈活擴展。
爲了保證Prometheus的簡單性,Prometheus並無從自身集羣的維度來解決這些問題,而是定義了兩種接口,remote_write/remote_read,將數據拋出去,你本身處理。
Prometheus的remote_storage 實際上是一個adapter,至於在adapter的另外一端是什麼類型的時序數據庫它根本不關心,若是你願意,你也能夠編寫本身的adpater。
如:存儲的方式爲:Prometheus —-發送數據—- > remote_storage_adapter —- 存儲數據 —-> influxdb。
prometheus經過下面兩種方式來實現與其餘的遠端存儲系統對接:
在遠程讀的流程當中,當用戶發起查詢請求後,Promthues將向remote_read中配置的URL發起查詢請求(matchers,ranges),Adaptor根據請求條件從第三方存儲服務中獲取響應的數據。同時將數據轉換爲Promthues的原始樣本數據返回給Prometheus Server。
當獲取到樣本數據後,Promthues在本地使用PromQL對樣本數據進行二次處理。
用戶能夠在Promtheus配置文件中指定Remote Write(遠程寫)的URL地址,一旦設置了該配置項,Prometheus將樣本數據經過HTTP的形式發送給適配器(Adaptor)。而用戶則能夠在適配器中對接外部任意的服務。外部服務能夠是真正的存儲系統,公有云的存儲服務,也能夠是消息隊列等任意形式。
配置很是簡單,只須要將對應的地址配置下就行
remote_write: - url: "http://localhost:9201/write" remote_read: - url: "http://localhost:9201/read"
如今社區已經實現瞭如下的遠程存儲方案
可使用讀寫完整的InfluxDB,咱們使用了多prometheus server同時遠程讀+寫,驗證了速度仍是能夠的。而且InfluxDB生態完整,自帶了不少管理工具。
在通常狀況下,Prometheus中存儲的每個樣本大概佔用1-2字節大小。若是須要對Prometheus Server的本地磁盤空間作容量規劃時,能夠經過如下公式計算:
磁盤大小 = 保留時間 * 每秒獲取樣本數 * 樣本大小
保留時間(retention_time_seconds)和樣本大小(bytes_per_sample)不變的狀況下,若是想減小本地磁盤的容量需求,只能經過減小每秒獲取樣本數(ingested_samples_per_second)的方式。
所以有兩種手段,一是減小時間序列的數量,二是增長採集樣本的時間間隔。
考慮到Prometheus會對時間序列進行壓縮,所以減小時間序列的數量效果更明顯。
遠程讀寫解決了Promtheus的數據持久化問題。使其能夠進行彈性擴展。另外還支持聯邦集羣模式,用於解決橫向擴展、網絡分區的問題(如地域A+B+C的監控數據,統一彙總到D),聯邦集羣的配置將在後面的Promthues高可用文章中詳細說明。
附:kubecon2018上講Prometheus 2.0的帥哥
還有一本專門講Prometheus的書:Prometheus: Up & Running(600多頁...)
國內沒找到賣的,找到了一本英文pdf的,還在翻譯理解中,有新的內容會繼續同步在這個系列博客
。。。又找到一本:https://www.prometheusbook.com/
本文爲容器監控實踐系列文章,完整內容見:container-monitor-book