1. 程式人生 > >剖析Prometheus的內部儲存機制

剖析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去恢復資料。