剖析Prometheus的內部儲存機制
Prometheus有著非常高效的時間序列資料儲存方法,每個取樣資料僅僅佔用3.5byte左右空間,上百萬條時間序列,30秒間隔,保留60天,大概花了200多G(引用官方PPT)。
接下來讓我們看看他的原理。
Prometheus內部主要分為三大塊,Retrieval是負責定時去暴露的目標頁面上去抓取取樣指標資料,Storage是負責將取樣資料寫磁碟,PromQL是Prometheus提供的查詢語言模組。
從最原始的抓取資料上來看,基本是這個樣子,timestamp是當前抓取時間戳:
每個Metric name代表了一類的指標,他們可以攜帶不同的Labels,每個Metric name + Label組合成代表了一條時間序列的資料。
例如圖上的資料:
http_requests_total{status="200",method="GET"}
http_requests_total{status="404",method="GET"}
表示了兩條不同的時間序列。
在Prometheus的世界裡面,所有的數值都是64bit的。每條時間序列裡面記錄的其實就是64bit timestamp(時間戳) + 64bit value(取樣值)。
而對於時間序列的基本特性來說,通常是過去的資料一般是隻讀的,是不會變更的,當前時間的資料才會可能在寫,模式如下圖:
根據上面的分析,時間序列的儲存似乎可以設計成key-value儲存的方式(基於BigTable)。
進一步拆分,可以像下面這樣子:
上圖的第二條樣式就是現在Prometheus內部的表現形式了,__name__是特定的label標籤,代表了metric name。
再回顧一下Prometheus的整體流程:
上面提到了K-V儲存,當然是使用了LevelDB的引擎,它的特點是順序讀寫效能非常高,這是非常符合時間序列的儲存的。
為了得到順序的時間序列雜湊索引值,Prometheus是這樣處理的:
FNV雜湊演算法全名為Fowler-Noll-Vo演算法,是以三位發明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字來命名的,最早在1991年提出。
FNV能快速hash大量資料並保持較小的衝突率,它的高度分散使它適用於hash一些非常相近的字串,比如URL,hostname,檔名,text,IP地址等。
1KB Chunks
在Prometheus的世界中,無論是記憶體還是磁碟,它都是以1KB單位分成塊來操作的。(新出的Prometheus 2.0對儲存底層做了很大改動,專門針對SSD的寫放大進行了優化,提高SSD的讀寫效能和讀寫次數等。)
整體流程是 抓取資料 -> 寫到head chunk,寫滿1KB,就再生成新的塊,完成的塊,是不可再變更的 -> 根據配置檔案的設定,有一部份chunk會被保留在記憶體裡,按照LRU演算法,定期將塊寫進磁碟檔案內。
注意: 一條時間序列,儲存到一個磁碟檔案內。
時間序列的保留維護
在Prometheus的啟動選項中,有一項storage.local.retention
可以設定資料自動保留多長時間,例如24h,表示資料超過24小時內的將會自動清除,類似於zabbix的housekeeping功能。storage.local.series-file-shrink-ratio
可以按一定的比例保留資料。
關於Chunk 塊編碼的剖析
Prometheus 提供三種不同型別的塊編碼,使用者可以在Prometheus啟動時指定最新的編碼方式,-storage.local.chunk-encoding-version
,有效值是0,1,2。
版本0的編碼是較老版本上的Prometheus上使用的,新版本已經不再建議使用的。
版本1是當前版本預設提供的編碼方式,它相對於0版有較好的壓縮能力,而且在一個塊內,有較高的訪問速度,當然版本0的編碼速度是最快的,但是相對版本1,速度優勢不是特別明顯。
版本2提供了一個更高的壓縮比例,編碼和解碼需要耗更多的CPU,當然,這是取決於查詢的資料集有多大。通常如果是較少的查詢,僅用於存檔的資料,可以使用這種編碼。
對比:
Chunk版本號 | 每個取樣點所佔位元組 | 耗CPU核 | 塊編碼耗時 |
---|---|---|---|
1 | 3.3 | 1.6 | 2.9s |
2 | 1.3 | 2.4 | 4.9s |
V0 結構
V1 結構
V2 結構
Prometheus是如何訪止資料丟失的呢?例如發生異常關閉或者什麼別的情況?它提供了一個Checkpointing功能,對於記憶體裡面的塊,Prometheus 使用了一個checkpoint file 去同步寫入磁碟,類似於Hbase的WAL原理,當發生crash時,先從checkpoint file去恢復資料。