百度時序資料庫——儲存的省錢之道

AIOps智慧運維發表於2019-03-04

作者簡介:任傑    百度高階研發工程師

負責百度智慧運維產品(Noah)的分散式時序資料儲存設計研發工作,在大規模分散式儲存、NoSQL資料庫方面有大量實踐經驗。


乾貨概覽

百度Noah平臺的TSDB,是百度最大規模的時序資料庫,它為Noah監控系統提供時序資料儲存與查詢服務,每天承接多達數萬億次的資料點寫入請求,以及數十億次的查詢請求。作為監控系統的後端服務,在如此大規模的寫入情況下,保證快速的查詢響應非常重要,這對系統提出了巨大挑戰。透過對使用者日常查詢行為進行分析,使用者的查詢需求與資料的時間軸有強關聯,使用者更加關心最近產生的資料。因此Noah的TSDB在架構上,利用百度BDRP(百度的Redis平臺)構建快取層,快取最近幾小時的資料,極大提升查詢效能,有效降低查詢平響。

同樣Facebook為了提高其ODS TSDB讀寫效能,設計了基於記憶體的Gorilla時序資料庫,用作ODS的write-through cache方案快取資料。可以看出在快取這層,我們都採用基於記憶體的方式做資料快取。採用記憶體最大的優勢是其資料讀寫速度遠快於磁碟速度,然而缺點是需要佔用較大的記憶體空間資源。為了有效節約記憶體空間,Gorilla設計了時序資料壓縮演算法對時序資料進行實時壓縮。在Gorilla論文[1]中表明,利用其壓縮演算法,在Facebook的生產環境下平均壓縮資料10倍。

我們在對快取層資料儲存設計的時候,結合Noah TSDB的具體情況,借鑑了Gorilla資料壓縮演算法對資料進行壓縮,儲存空間資源佔用降低了70%,有效降低資源成本。因此本文簡單和大家分享一下該壓縮演算法的基本原理,沒準兒也能節約下不少錢呢。

基礎介紹

典型的時序資料,是由Key-Value組成的二元組, Key中可能包含如Cluster、Tag、Metric、Timestamp等資訊。為了便於理解,這裡將時序資料簡單理解為Key是時間戳(Timestamp),Value是在該時間戳時的具體資料值。

假設這是某CPU在不同時間的利用率:

百度時序資料庫——儲存的省錢之道

以這份資料為例,在後續介紹中我們一邊介紹演算法,一邊採用Gorilla的壓縮方法對這個測試資料進行壓縮,觀察該演算法壓縮效果。

壓縮思想


1基本原則

Gorilla壓縮演算法,其核心思想建立在時序資料場景下,相鄰的時序資料相似度很大這一特點之上。基於這個基本的原則,儘量只保留資料差異的部分,去除相同的部分,來達到壓縮資料的目的。

2資料結構

Gorilla將資料組織成一個個資料塊(Block),一個Block儲存連續一段時間且經過壓縮的時序資料。每次查詢的時候會直接讀取目標資料所屬的Block,對Block解壓後返回查詢結果。Facebook經驗表明,如果一個Block的時間跨度超過2小時,由於解壓Block所消耗的資源增加,其壓縮收益會逐漸降低,因此將單個Block的時間跨度設定為2小時。

每個Block的Header儲存其起始時間戳(Timebase),例如如果某時序資料產生時間點是2019/2/24 14:30,則以2小時為單位向上取整,該資料所屬的Block的Timebase為2019/2/24 14:00,時間戳為1550944800如下圖所示。然後以KV的形式依次儲存屬於該Block的時序資料。

百度時序資料庫——儲存的省錢之道

接下來分別介紹對Key和Value的壓縮方法。

時間戳壓縮

時序資料的產生,大部分都有固定的產生時間間隔,如間隔10s、15s、60s等。即使由於各種因素造成時序資料產生有一定延遲或者提前,但是大部分資料的時間戳間隔都是在非常接近的範圍內。因此對時間戳壓縮的思想就是不需要儲存完整的時間戳,只儲存時間戳差值的差值(delta of delta)。具體以本文測試資料的時間戳Key為例介紹時間戳壓縮演算法。

  • 壓縮前

每個秒級的時間戳用Long型儲存(8Bytes),本文測試資料中的3條資料時間戳共需要佔用3*8*8 = 192(Bits)。T均為Unix 時間戳。

  • Gorilla壓縮

對於每個Block:

  1. Block的頭部Header儲存本Block的起始時間戳百度時序資料庫——儲存的省錢之道,不做任何壓縮。

  2. 第一個時間戳儲存 百度時序資料庫——儲存的省錢之道百度時序資料庫——儲存的省錢之道的差值(Delta),佔用14(Bits)。

  3. 對於本Block後面的時間戳百度時序資料庫——儲存的省錢之道

    1. 計算差值的差值:

      百度時序資料庫——儲存的省錢之道

    2. 存在Block中時間戳資料由 [標識位+D值] 組成,根據D的不同範圍確定標識位的取值和儲存D值所需佔用的空間。如下表所示:

百度時序資料庫——儲存的省錢之道

具體對於本例而言,採用上述對時間戳的壓縮方式後結果如下所示:

百度時序資料庫——儲存的省錢之道

利用上述的壓縮編碼方式對本文的測試資料編碼後,其所屬的Block內資料如下所示:

百度時序資料庫——儲存的省錢之道

其中只填寫了T的部分,V的部分由下文進行補充。經過壓縮測試資料,總共佔用64+14+9+1=88(Bits),壓縮率為88/192=45.8%。

由於本例的測試資料較少,Header空間佔比較大,導致壓縮收益與實際環境中收益有一定差距。在實際環境中,Header所佔有的空間相對於整個Block來說比例較小,壓縮收益會更大。根據Facebook線上資料統計,如下圖所示,96%的時間戳都被壓縮到1個Bit來儲存,因此在生產環境將會帶來不錯的壓縮收益(結合資料分佈再回過頭看編碼方式,是不是有點Huffman編碼的感覺)。

百度時序資料庫——儲存的省錢之道

資料值壓縮

對時間戳Key壓縮後,接下來對Value進行壓縮。與Key類似,透過對歷史資料進行分析,發現大部分相鄰時間的時序資料的Value值比較接近(可以理解為突增/突降的現象比較少)。而如果Value的值比較接近,則在浮點二進位制表示的情況下,相鄰資料的Value會有很多相同的位。整數型資料的相同位會更多。相同位比較多,意味著如果進行XOR運算的話會有很多位都為0。

為了便於說明,這裡首先定義一個XOR運算後的結果由三部分組成:

百度時序資料庫——儲存的省錢之道

  • Leading Zeros(LZ): XOR後第一個非零位前面零的個數

  • Trailing Zeros(TZ): XOR後最後一個非零位後面零的個數

  • Meaningful Bits(MB): 中間有效位的個數

上圖是Gorilla論文裡給的示例,可以理解該資料為一系列相鄰時序資料的Value。可以看出對相鄰資料進行XOR運算後,MB、LZ和TZ非常相似。基於此,其壓縮方式參考之前其他工作[2,3]已經提出的資料壓縮方法,將當前值與前序值取XOR(異或)運算,儲存XOR運算結果。具體方式如下:

百度時序資料庫——儲存的省錢之道

  • 壓縮前

每個浮點型別資料Double型儲存佔用8Bytes,本文測試資料中的3條資料Value共需要佔用3*8*8 = 192(Bits)。

  • Gorilla壓縮

在同一個Block內,Value的壓縮規則如下:

  1. 第一個Value的值百度時序資料庫——儲存的省錢之道不壓縮。

  2. 對於本資料塊後面的Value值百度時序資料庫——儲存的省錢之道

    1. XOR運算結果:百度時序資料庫——儲存的省錢之道

    2. 百度時序資料庫——儲存的省錢之道結果進行如下處理:

百度時序資料庫——儲存的省錢之道

基於上述壓縮編碼規則,對本文測試資料的Value進行壓縮後結果如下所示,壓縮後總共佔用64+1+1+14 = 80(Bits),壓縮率為80/256=31.2%。

百度時序資料庫——儲存的省錢之道

此時該Block內的資料如下所示:

百度時序資料庫——儲存的省錢之道

以上就是對於Value值的壓縮方法。與Key的壓縮一樣,線上上環境資料量較多的情況下壓縮效果會更好。根據Facebook線上資料統計,59.06%的value值都被壓縮到1個位來儲存。

百度時序資料庫——儲存的省錢之道

總  結

總的來說,利用上述的壓縮方式,我們的測試資料由384Bits(Key+Value)變為168Bits,壓縮率達到43%,具有不錯的壓縮效率。當然由於資料量的原因,在實際生產環境下壓縮收益會更大。百度Noah的TSDB在應用上述壓縮演算法的實踐中,基於我們的實際情況進行了一定的改造(後續序列文章會另行介紹),儲存空間的資源佔用減少超過70%,表明這個演算法能真實有效對時序資料進行壓縮。

另外一點,我們發現在做壓縮的時候Gorilla對Key和Value分開進行了壓縮處理。將Key和Value分開壓縮的好處在於,可以根據Key、Value不同的資料型別、資料特點,選用更適合自己的壓縮演算法,從而提高壓縮效率。在時序場景下,KV分別處理雖然不是一個新的思想,但是可以將該思想應用在多個地方。比如本文提到的Gorilla是將該思想應用在壓縮方面,FAST2016年的WiscKey[4]利用KV分離思想最佳化LSM的IO放大問題。有興趣的讀者可以針對KV分離方法探索一下。

由於本人水平有限,若理解不到位或者大家有任何想法,歡迎指出交流。

參考文獻

1. Pelkonen T , Franklin S , Teller J , et al. Gorilla: A Fast, Scalable, In-Memory Time Series Database[J]. Proceedings of the Vldb Endowment, 2015, 8(12):1816-1827.

2. P. Lindstrom and M. Isenburg. Fast and Efficient Compression of Floating-Point Data. Visualization and Computer Graphics, IEEE Transactions on, 12(5):1245–1250, 2006.

3. P. Ratanaworabhan, J. Ke, and M. Burtscher. Fast Lossless Compression of Scientific Floating-Point Data. In DCC, pages 133–142. IEEE Computer Society, 2006.

4. Lu L , Pillai T S , Gopalakrishnan H , et al. WiscKey: Separating Keys from Values in SSD-Conscious Storage[J]. ACM Transactions on Storage, 2017, 13(1):1-28.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31557835/viewspace-2637499/,如需轉載,請註明出處,否則將追究法律責任。

相關文章