一. 引言
Prometheus 是一款開源的監(jiān)控與報(bào)警系統(tǒng),支持對(duì)海量監(jiān)控?cái)?shù)據(jù)的抓取與查詢。在部署 Prometheus 服務(wù)之前,對(duì)服務(wù)的存儲(chǔ)用量進(jìn)行規(guī)劃是十分重要的。否則,運(yùn)維人員無法對(duì)業(yè)務(wù)數(shù)據(jù)的規(guī)模和所需存儲(chǔ)資源的量級(jí)獲得直觀認(rèn)識(shí)。分配的存儲(chǔ)資源過多,會(huì)導(dǎo)致資源閑置與成本浪費(fèi);分配的存儲(chǔ)容量不足,則無法應(yīng)對(duì)業(yè)務(wù)的增長,嚴(yán)重影響監(jiān)控服務(wù)的穩(wěn)定性。
部署 Prometheus 服務(wù)的第一個(gè)步驟是,整理與獲得需要監(jiān)控的節(jié)點(diǎn)集合。通過這一集合,我們可以計(jì)算出業(yè)務(wù)數(shù)據(jù)的規(guī)模。進(jìn)而,我們可以計(jì)算出,需要多少存儲(chǔ)資源來支撐監(jiān)控服務(wù)的運(yùn)行。
本文對(duì)影響 Prometheus 服務(wù)的運(yùn)行時(shí)存儲(chǔ)用量的各個(gè)因素進(jìn)行了剖析與討論,并給出若干經(jīng)驗(yàn)公式。這些公式可以用于預(yù)估監(jiān)控服務(wù)的內(nèi)存和硬盤用量。
二. 計(jì)算樣本總量
首先明確兩個(gè)名詞,監(jiān)控節(jié)點(diǎn)與測量點(diǎn)。
- 監(jiān)控節(jié)點(diǎn)。一個(gè) exporter 進(jìn)程被認(rèn)為是一個(gè)監(jiān)控節(jié)點(diǎn)。一臺(tái)主機(jī)上可能運(yùn)行多個(gè)不同類型的 exporter,因此,這臺(tái)主機(jī)上存在多個(gè)監(jiān)控節(jié)點(diǎn)。
- 測量點(diǎn)。一個(gè)測量點(diǎn)代表了某監(jiān)控節(jié)點(diǎn)上的一個(gè)觀測對(duì)象。從某測量點(diǎn)采集到的一組樣本數(shù)據(jù)構(gòu)成一條時(shí)間序列(time series)。
為了預(yù)估存儲(chǔ)用量,首先需要計(jì)算樣本數(shù)據(jù)的總量。我們約定:
- 需要監(jiān)控的節(jié)點(diǎn)集合為 $$nodes={i|i>0}$$
- 節(jié)點(diǎn) i 上的測量點(diǎn)的數(shù)目為 $$metrics(i)$$
- 對(duì)節(jié)點(diǎn) i 的抓取時(shí)間間隔為 $$interval(i)$$,一般為所有節(jié)點(diǎn)設(shè)置相同的抓取間隔
每個(gè)節(jié)點(diǎn)上的測量點(diǎn)的數(shù)目由所使用的具體的 exporter 定義。特別的:
- Node Exporter 有 251 個(gè)測量點(diǎn)
- Prometheus 服務(wù)本身有 775 個(gè)測量點(diǎn)
抓取間隔越大,數(shù)據(jù)越稀疏;抓取間隔越小,監(jiān)控?cái)?shù)據(jù)的時(shí)間分辨率越高,但所需的存儲(chǔ)資源會(huì)增多。建議將該值設(shè)置在 5s ~ 15s 之間。
基于上述約定可得,在特定的時(shí)間范圍 $$duration$$ 內(nèi),Prometheus 從節(jié)點(diǎn)集合中所抓取的樣本數(shù)據(jù)的總量依下式計(jì)算:
$$sample_count(duration)=\sum_{i \in nodes}{(metrics(i) \times \frac{duration}{interval(i)})}$$
Prometheus 支持三種不同的數(shù)據(jù)編碼方案。第一種方案是 delta 編碼,已被棄用;第二種方案是 double-delta 編碼,這也是默認(rèn)使用的編碼方案;第三種方案是 varbit 編碼,基于 Facebook 的一篇關(guān)于時(shí)序數(shù)據(jù)庫的論文。varbit 編碼方案雖能提高數(shù)據(jù)壓縮率,卻顯著增大了編解碼的運(yùn)算時(shí)間。除非有特殊場景,否則我們使用 double-delta 編碼方案。
由 Prometheus 的官方文檔,使用 double-delta 方案對(duì)數(shù)據(jù)進(jìn)行編碼后,每條樣本的字節(jié)大小為:
$$sample_size=3.3B$$
經(jīng)過若干次采樣測量,觀測到的平均樣本大小介于 3.0~3.8B 之間。可以認(rèn)為 3.3B 的單條樣本大小是可信的。
三. 規(guī)劃內(nèi)存用量
Prometheus 對(duì)內(nèi)存的使用由以下四個(gè)部分組成:
- 留存于內(nèi)存的活躍樣本
- 排隊(duì)等待持久化的過期樣本
- 索引數(shù)據(jù)
- 其他運(yùn)行時(shí)內(nèi)存消耗
第 3.1 節(jié)討論樣本數(shù)據(jù)的內(nèi)存用量(前兩部分),第 3.2 節(jié)討論索引數(shù)據(jù)的內(nèi)存用量。對(duì)于其他的運(yùn)行時(shí)內(nèi)存消耗,本文不予討論。
3.1 為樣本數(shù)據(jù)計(jì)算內(nèi)存用量
3.1.1 留存于內(nèi)存的活躍樣本
對(duì)于活躍樣本,假設(shè)我們要求的留存時(shí)間為 $$mem_retention$$,則所需的內(nèi)存空間為:
$$sample_mem_1=sample_size \times sample_count(mem_retention)$$
在內(nèi)存中的留存數(shù)據(jù)越多,查詢過往數(shù)據(jù)的性能越高。但是,新數(shù)據(jù)的價(jià)值遠(yuǎn)遠(yuǎn)高于過往數(shù)據(jù)。在實(shí)際應(yīng)用中,需要根據(jù)所監(jiān)控的業(yè)務(wù)的性質(zhì),設(shè)定合理的內(nèi)存留存時(shí)間。Facebook 在其論文中給出的經(jīng)驗(yàn)值是 26h。建議將該值設(shè)置在 6h ~ 48h 之間。
3.1.2 排隊(duì)等待持久化的過期樣本
對(duì)于排隊(duì)樣本,我們約定:
- 為了完成對(duì)當(dāng)前所有排隊(duì)樣本的持久化,Prometheus 需要花費(fèi)的時(shí)間周期為 $$persist_cycle$$
- 為了不至于使 Prometheus 進(jìn)入緊急模式(Rush mode),排隊(duì)樣本所占的空間不應(yīng)超過預(yù)估空間的 $$80%$$
一般情況下,持久化的時(shí)間周期為 6 個(gè)小時(shí):
$$persist_cycle=6h$$
因此,排隊(duì)樣本所需的內(nèi)存空間為:
$$sample_mem_2=\frac{sample_size \times sample_count(persist_cycle)}{0.8}$$
3.1.3 匯總
基于前兩個(gè)公式,再加上索引數(shù)據(jù)的內(nèi)存用量(參見第 3.2 節(jié)),總內(nèi)存用量可以依下式計(jì)算:
$$mem=sample_mem_1+sample_mem_2+index_mem$$
一條經(jīng)驗(yàn)法則為,總內(nèi)存用量不應(yīng)超過物理內(nèi)存大小的三分之二。
下表計(jì)算了若干典型的內(nèi)存用量(假設(shè)所有節(jié)點(diǎn)均為 Node Exporter 節(jié)點(diǎn)):
| 節(jié)點(diǎn)數(shù)目 | 內(nèi)存留存 | 抓取間隔 | 活躍樣本量 | 排隊(duì)樣本量 | 內(nèi)存用量 | 物理內(nèi)存 |
|---|---|---|---|---|---|---|
| 100 | 6h | 1s | 1.789G | 2.237G | 4.026G | 6G |
| 100 | 6h | 5s | 0.358G | 0.447G | 0.805G | 1.5G |
| 1000 | 6h | 5s | 3.58G | 0.447G | 4.027G | 6G |
| 100 | 24h | 1s | 7.156G | 2.237G | 9.393G | 14G |
| 100 | 24h | 5s | 1.432G | 0.447G | 1.879G | 3G |
| 1000 | 24h | 5s | 14.32G | 0.447G | 14.75G | 22G |
3.2 為索引數(shù)據(jù)計(jì)算內(nèi)存用量
對(duì)索引數(shù)據(jù)所需內(nèi)存的估計(jì),可以使用下面的經(jīng)驗(yàn)公式:
$$index_mem=\frac{series_count}{1000}MB$$
其中,
$$series_count=\sum_{i \in nodes}{metrics(i)}$$
也就是,如果有 1000 個(gè)時(shí)間序列,大約需要 1M 內(nèi)存。為了提高對(duì)舊數(shù)據(jù)查詢性能,可以適當(dāng)增大索引內(nèi)存。
四. 規(guī)劃硬盤用量
4.1 為樣本數(shù)據(jù)計(jì)算硬盤用量
Prometheus 將樣本數(shù)據(jù)持久化為若干文件。當(dāng)文件中的過期數(shù)據(jù)超過一定比率時(shí),Prometheus 會(huì)對(duì)文件執(zhí)行收縮操作。這個(gè)比率被稱為文件的收縮比,默認(rèn)值為 $$10%$$。留存時(shí)間設(shè)置的越大,文件的收縮比應(yīng)該相應(yīng)地上調(diào)。
假設(shè)我們要求樣本留存時(shí)間為 $$disk_retension$$,文件的收縮比為 $$shrink_ratio$$,則樣本的硬盤用量為:
$$sample_disk=\frac{sample_size \times sample_count(disk_retention)}{1+shrink_ratio}$$
加上存儲(chǔ)檢查點(diǎn)所需的硬盤空間(參加第 4.2 節(jié)),總硬盤用量為:
$$disk=sample_disk+checkpoint_disk$$
下表計(jì)算了若干典型的硬盤用量(假設(shè)所有節(jié)點(diǎn)均為 Node Exporter 節(jié)點(diǎn)),注意,該表未包含存儲(chǔ) checkpoint 所需要的硬盤空間:
| 節(jié)點(diǎn)數(shù)目 | 留存時(shí)間 | 抓取間隔 | 硬盤用量 |
|---|---|---|---|
| 100 | 14d | 1s | 91G |
| 100 | 14d | 5s | 18G |
| 1000 | 14d | 1s | 910G |
| 1000 | 14d | 5s | 180G |
4.2 為檢查點(diǎn)(Checkpoint)計(jì)算硬盤用量
檢查點(diǎn)操作用于將內(nèi)存中的活躍樣本暫存到某硬盤文件中,以減少由于程序崩潰或機(jī)器掉電等引起的數(shù)據(jù)丟失。其硬盤用量與活躍樣本的內(nèi)存用量持平即可:
$$checkpoint_disk=sample_mem_1$$
五. 總結(jié)
本文中,我們首先討論了如何計(jì)算所觀測的樣本總量。特別的,Node Exporter 有 251 個(gè)測量點(diǎn),Prometheus 服務(wù)本身有 775 個(gè)測量點(diǎn)。
進(jìn)行內(nèi)存用量規(guī)劃時(shí),我們主要關(guān)注留存于內(nèi)存中的活躍樣本與位于持久化隊(duì)列中的過期樣本。索引數(shù)據(jù)所需的內(nèi)存較少,一個(gè)經(jīng)驗(yàn)公式為,每一千個(gè)時(shí)間序列大約需要 1M 內(nèi)存。
Prometheus 對(duì)硬盤的使用主要集中在對(duì)樣本數(shù)據(jù)的持久化上。當(dāng)文件過大時(shí),Prometheus 會(huì)對(duì)文件執(zhí)行收縮操作。收縮操作的觸發(fā)由文件的收縮比控制,該選項(xiàng)的默認(rèn)值為 $$10%$$。
請(qǐng)注意,數(shù)據(jù)對(duì)內(nèi)存和硬盤的使用情況由眾多因素共同影響,例如,數(shù)據(jù)本身的性質(zhì),內(nèi)存性能,硬盤性能,垃圾回收機(jī)制,內(nèi)存碎片等。對(duì)存儲(chǔ)用量作出準(zhǔn)確的預(yù)估是困難的。本文給出的公式在評(píng)估數(shù)據(jù)量級(jí)時(shí)有參考意義,對(duì)于實(shí)際的調(diào)優(yōu)工作,還需要對(duì)線上環(huán)境進(jìn)行深入而詳盡的觀察和測量之后方可完成。