时序数据库连载系列: 时序数据库一哥InfluxDB之存储机制解析
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
InfluxDB 的存儲(chǔ)機(jī)制解析
本文介紹了InfluxDB對(duì)于時(shí)序數(shù)據(jù)的存儲(chǔ)/索引的設(shè)計(jì)。由于InfluxDB的集群版已在0.12版就不再開(kāi)源,因此如無(wú)特殊說(shuō)明,本文的介紹對(duì)象都是指 InfluxDB?單機(jī)版
1. InfluxDB 的存儲(chǔ)引擎演進(jìn)
盡管InfluxDB自發(fā)布以來(lái)歷時(shí)三年多,其存儲(chǔ)引擎的技術(shù)架構(gòu)已經(jīng)做過(guò)幾次重大的改動(dòng), 以下將簡(jiǎn)要介紹一下InfluxDB的存儲(chǔ)引擎演進(jìn)的過(guò)程。
1.1 演進(jìn)簡(jiǎn)史
- 版本0.9.0之前
**基于 LevelDB的LSMTree方案** - 版本0.9.0~0.9.4
**基于BoltDB的mmap COW B+tree方案** - 版本0.9.5~1.2
**基于自研的 WAL + TSMFile 方案**(TSMFile方案是0.9.6版本正式啟用,0.9.5只是提供了原型) - 版本1.3~至今
**基于自研的 WAL + TSMFile + TSIFile 方案**
1.2 演進(jìn)的考量
InfluxDB的存儲(chǔ)引擎先后嘗試過(guò)包括LevelDB, BoltDB在內(nèi)的多種方案。但是對(duì)于InfluxDB的下述訴求終不能完美地支持:
- 時(shí)序數(shù)據(jù)在降采樣后會(huì)存在大批量的數(shù)據(jù)刪除
=> *LevelDB的LSMTree刪除代價(jià)過(guò)高* - 單機(jī)環(huán)境存放大量數(shù)據(jù)時(shí)不能占用過(guò)多文件句柄
=> *LevelDB會(huì)隨著時(shí)間增長(zhǎng)產(chǎn)生大量小文件* - 數(shù)據(jù)存儲(chǔ)需要熱備份
=> *LevelDB只能冷備* - 大數(shù)據(jù)場(chǎng)景下寫(xiě)吞吐量要跟得上
=> *BoltDB的B+tree寫(xiě)操作吞吐量成瓶頸* - 存儲(chǔ)需具備良好的壓縮性能
=> *BoltDB不支持壓縮*
此外,出于技術(shù)棧的一致性以及部署的簡(jiǎn)易性考慮(面向容器部署),InfluxDB團(tuán)隊(duì)希望存儲(chǔ)引擎 與 其上層的TSDB引擎一樣都是用GO編寫(xiě),因此潛在的RocksDB選項(xiàng)被排除
基于上述痛點(diǎn),InfluxDB團(tuán)隊(duì)決定自己做一個(gè)存儲(chǔ)引擎的實(shí)現(xiàn)。
2 InfluxDB的數(shù)據(jù)模型
在解析InfluxDB的存儲(chǔ)引擎之前,先回顧一下InfluxDB中的數(shù)據(jù)模型。
在InfluxDB中,時(shí)序數(shù)據(jù)支持多值模型,它的一條典型的時(shí)間點(diǎn)數(shù)據(jù)如下所示:
圖 1
?
- measurement:
指標(biāo)對(duì)象,也即一個(gè)數(shù)據(jù)源對(duì)象。每個(gè)measurement可以擁有一個(gè)或多個(gè)指標(biāo)值,也即下文所述的**field**。在實(shí)際運(yùn)用中,可以把一個(gè)現(xiàn)實(shí)中被檢測(cè)的對(duì)象(如:“cpu”)定義為一個(gè)measurement - tags:
概念等同于大多數(shù)時(shí)序數(shù)據(jù)庫(kù)中的tags, 通常通過(guò)tags可以唯一標(biāo)示數(shù)據(jù)源。每個(gè)tag的key和value必須都是字符串。 - field:
數(shù)據(jù)源記錄的具體指標(biāo)值。每一種指標(biāo)被稱(chēng)作一個(gè)“field”,指標(biāo)值就是 “field”對(duì)應(yīng)的“value” - timestamp:
數(shù)據(jù)的時(shí)間戳。在InfluxDB中,理論上時(shí)間戳可以精確到 **納秒**(ns)級(jí)別
此外,在InfluxDB中,measurement的概念之上還有一個(gè)對(duì)標(biāo)傳統(tǒng)DBMS的?Database?的概念,邏輯上每個(gè)Database下面可以有多個(gè)measurement。在單機(jī)版的InfluxDB實(shí)現(xiàn)中,每個(gè)Database實(shí)際對(duì)應(yīng)了一個(gè)文件系統(tǒng)的?目錄。
2.1 Serieskey的概念
InfluxDB中的SeriesKey的概念就是通常在時(shí)序數(shù)據(jù)庫(kù)領(lǐng)域被稱(chēng)為?時(shí)間線?的概念, 一個(gè)SeriesKey在內(nèi)存中的表示即為下述字符串(逗號(hào)和空格被轉(zhuǎn)義)的?字節(jié)數(shù)組(http://github.com/influxdata/influxdb/model#MakeKey())
{measurement名}{tagK1}={tagV1},{tagK2}={tagV2},...其中,SeriesKey的長(zhǎng)度不能超過(guò) 65535 字節(jié)
2.2 支持的Field類(lèi)型
InfluxDB的Field值支持以下數(shù)據(jù)類(lèi)型:
DatatypeSize in MemValue RangeFloat8 bytes1.797693134862315708145274237317043567981e+308 ~ 4.940656458412465441765687928682213723651e-324Integer8 bytes-9223372036854775808 ~ 9223372036854775807String0~64KBString with length less than 64KBBoolean1 bytetrue 或 false
在InfluxDB中,Field的數(shù)據(jù)類(lèi)型在以下范圍內(nèi)必須保持不變,否則寫(xiě)數(shù)據(jù)時(shí)會(huì)報(bào)錯(cuò)?類(lèi)型沖突。
同一Serieskey + 同一field + 同一shard2.3 Shard的概念
在InfluxDB中,?能且只能?對(duì)一個(gè)Database指定一個(gè)?Retention Policy?(簡(jiǎn)稱(chēng):RP)。通過(guò)RP可以對(duì)指定的Database中保存的時(shí)序數(shù)據(jù)的留存時(shí)間(duration)進(jìn)行設(shè)置。而?Shard?的概念就是由duration衍生而來(lái)。一旦一個(gè)Database的duration確定后, 那么在該Database的時(shí)序數(shù)據(jù)將會(huì)在這個(gè)duration范圍內(nèi)進(jìn)一步按時(shí)間進(jìn)行分片從而時(shí)數(shù)據(jù)分成以一個(gè)一個(gè)的shard為單位進(jìn)行保存。
shard分片的時(shí)間 與 duration之間的關(guān)系如下
Duration of RPShard Duration< 2 Hours1 Hour>= 2 Hours 且 <= 6 Months1 Day> 6 Months7 Days
新建的Database在未顯式指定RC的情況下,默認(rèn)的RC為?數(shù)據(jù)的Duration為永久,Shard分片時(shí)間為7天
注: 在閉源的集群版Influxdb中,用戶(hù)可以通過(guò)RC規(guī)則指定數(shù)據(jù)在基于時(shí)間分片的基礎(chǔ)上再按SeriesKey為單位進(jìn)行進(jìn)一步分片
3. InfluxDB的存儲(chǔ)引擎分析
時(shí)序數(shù)據(jù)庫(kù)的存儲(chǔ)引擎主要需滿(mǎn)足以下三個(gè)主要場(chǎng)景的性能需求
InfluxDB在結(jié)合了1.2所述考量的基礎(chǔ)上推出了他們的解決方案,即下面要介紹的?WAL + TSMFile + TSIFile的方案
3.1 WAL解析
InfluxDB寫(xiě)入時(shí)序數(shù)據(jù)時(shí)為了確保數(shù)據(jù)完整性和可用性,與大部分?jǐn)?shù)據(jù)庫(kù)產(chǎn)品一樣,都是會(huì)先寫(xiě)WAL,再寫(xiě)入緩存,最后刷盤(pán)。對(duì)于InfluxDB而言,寫(xiě)入時(shí)序數(shù)據(jù)的主要流程如同下圖所示:
圖 2
?
InfluxDB對(duì)于時(shí)間線數(shù)據(jù)和時(shí)序數(shù)據(jù)本身分開(kāi),分別寫(xiě)入不同的WAL中,其結(jié)構(gòu)如下所示:
索引數(shù)據(jù)的WAL
由于InfluxDB支持對(duì)Measurement,TagKey,TagValue的刪除操作,當(dāng)然隨著時(shí)序數(shù)據(jù)的不斷寫(xiě)入,自然也包括?增加新的時(shí)間線,因此索引數(shù)據(jù)的WAL會(huì)區(qū)分當(dāng)前所做的操作具體是什么,它的WAL的結(jié)構(gòu)如下圖所示
圖 3
?
時(shí)序數(shù)據(jù)的WAL
由于InfluxDB對(duì)于時(shí)序數(shù)據(jù)的寫(xiě)操作永遠(yuǎn)只有單純寫(xiě)入,因此它的Entry不需要區(qū)分操作種類(lèi),直接記錄寫(xiě)入的數(shù)據(jù)即可
圖 4
?
3.2 TSMFile解析
TSMFile是InfluxDB對(duì)于時(shí)序數(shù)據(jù)的存儲(chǔ)方案。在文件系統(tǒng)層面,每一個(gè)TSMFile對(duì)應(yīng)了一個(gè)?Shard。
TSMFile的存儲(chǔ)結(jié)構(gòu)如下圖所示:
圖 5
?
其特點(diǎn)是在一個(gè)TSMFile中將 時(shí)序數(shù)據(jù)(i.e Timestamp + Field value)保存在數(shù)據(jù)區(qū);將Serieskey 和 Field Name的信息保存在索引區(qū),通過(guò)一個(gè)基于 Serieskey + Fieldkey構(gòu)建的形似B+tree的文件內(nèi)索引快速定位時(shí)序數(shù)據(jù)所在的?數(shù)據(jù)塊
注: 在當(dāng)前版本中,單個(gè)TSMFile的最大長(zhǎng)度為2GB,超過(guò)時(shí)即使是同一個(gè)Shard,也會(huì)繼續(xù)新開(kāi)一個(gè)TSMFile保存數(shù)據(jù)。本文的介紹出于簡(jiǎn)單化考慮,以下內(nèi)容不考慮同一個(gè)Shard的TSMFile分裂的場(chǎng)景
- 索引塊的構(gòu)成
上文的索引塊的構(gòu)成,如下所示:?*圖 6*
?
其中 **索引條目** 在InfluxDB的源碼中被稱(chēng)為`directIndex`。在TSMFile中,索引塊是按照 Serieskey + Fieldkey **排序** 后組織在一起的。明白了TSMFile的索引區(qū)的構(gòu)成,就可以很自然地理解InfluxDB如何高性能地在TSMFile掃描時(shí)序數(shù)據(jù)了:1. 根據(jù)用戶(hù)指定的時(shí)間線(Serieskey)以及Field名 在 **索引區(qū)** 利用二分查找找到指定的Serieskey+FieldKey所處的 **索引數(shù)據(jù)塊** 2. 根據(jù)用戶(hù)指定的時(shí)間戳范圍在 **索引數(shù)據(jù)塊** 中查找數(shù)據(jù)落在哪個(gè)(*或哪幾個(gè)*)**索引條目** 3. 將找到的 **索引條目** 對(duì)應(yīng)的 **時(shí)序數(shù)據(jù)塊** 加載到內(nèi)存中進(jìn)行進(jìn)一步的Scan*注:上述的1,2,3只是簡(jiǎn)單化地介紹了查詢(xún)機(jī)制,實(shí)際的實(shí)現(xiàn)中還有類(lèi)似掃描的時(shí)間范圍跨索引塊等一系列復(fù)雜場(chǎng)景*<br>- 時(shí)序數(shù)據(jù)的存儲(chǔ)
在圖 2中介紹了時(shí)序數(shù)據(jù)塊的結(jié)構(gòu):即同一個(gè) Serieskey + Fieldkey 的 所有時(shí)間戳 - Field值對(duì)被拆分開(kāi),分成兩個(gè)區(qū):Timestamps區(qū)和Value區(qū)分別進(jìn)行存儲(chǔ)。它的目的是:實(shí)際存儲(chǔ)時(shí)可以分別對(duì)時(shí)間戳和Field值按不同的壓縮算法進(jìn)行存儲(chǔ)以減少時(shí)序數(shù)據(jù)塊的大小
采用的壓縮算法如下所示:- Timestamp:?Delta-of-delta encoding
- Field Value:由于單個(gè)數(shù)據(jù)塊的Field Value必然數(shù)據(jù)類(lèi)型相同,因此可以集中按數(shù)據(jù)類(lèi)型采用不同的壓縮算法
- Float類(lèi):?Gorrila's Float Commpression
- Integer類(lèi)型: Delta Encoding + Zigzag Conversion + RLE / Simple8b / None
- String類(lèi)型:?Snappy Compression
- Boolean類(lèi)型: Bit packing
?
做查詢(xún)時(shí),當(dāng)利用TSMFile的索引找到文件中的時(shí)序數(shù)據(jù)塊時(shí),將數(shù)據(jù)塊載入內(nèi)存并對(duì)Timestamp以及Field Value進(jìn)行解壓縮后以便繼續(xù)后續(xù)的查詢(xún)操作。
3.3 TSIFile解析
有了TSMFile,第3章開(kāi)頭所說(shuō)的三個(gè)主要場(chǎng)景中的場(chǎng)景1和場(chǎng)景2都可以得到很好的解決。但是如果查詢(xún)時(shí)用戶(hù)并沒(méi)有按預(yù)期按照Serieskey來(lái)指定查詢(xún)條件,而是指定了更加復(fù)雜的條件,該如何確保它的查詢(xún)性能?通常情況下,這個(gè)問(wèn)題的解決方案是依賴(lài)倒排索引(Inverted Index)。
InfluxDB的倒排索引依賴(lài)于下述兩個(gè)數(shù)據(jù)結(jié)構(gòu)
- map<SeriesID, SeriesKey>
- map<tagkey, map<tagvalue, List<SeriesID>>>
它們?cè)趦?nèi)存中展現(xiàn)如下:
圖 7
?
圖 8
?
但是在實(shí)際生產(chǎn)環(huán)境中,由于用戶(hù)的時(shí)間線規(guī)模會(huì)變得很大,因此會(huì)造成倒排索引使用的內(nèi)存過(guò)多,所以后來(lái)InfluxDB又引入了?TSIFile
TSIFile的整體存儲(chǔ)機(jī)制與TSMFile相似,也是以?Shard?為單位生成一個(gè)TSIFile。具體的存儲(chǔ)格式就在此不贅述了。
4. 總結(jié)
以上就是對(duì)InfluxDB的存儲(chǔ)機(jī)制的粗淺解析,由于目前所見(jiàn)的只有單機(jī)版的InfluxDB,所以尚不知道集群版的InfluxDB在存儲(chǔ)方面有哪些不同。但是,即便是這單機(jī)版的存儲(chǔ)機(jī)制,也對(duì)我們?cè)O(shè)計(jì)時(shí)序數(shù)據(jù)庫(kù)有著重要的參考意義。
?
#阿里云開(kāi)年Hi購(gòu)季#幸運(yùn)抽好禮!
點(diǎn)此抽獎(jiǎng):【阿里云】開(kāi)年Hi購(gòu)季,幸運(yùn)抽好禮
?
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
轉(zhuǎn)載于:https://my.oschina.net/u/3889140/blog/3015136
總結(jié)
以上是生活随笔為你收集整理的时序数据库连载系列: 时序数据库一哥InfluxDB之存储机制解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: arcgis 坐标系 2000坐标系_干
- 下一篇: 删除对于job收缩日志失败547_MyS