清华自研时间序列数据库Apache IoTDB原理解析
云智慧 AIOps 社區(qū)是由云智慧發(fā)起,針對運維業(yè)務場景,提供算法、算力、數據集整體的服務體系及智能運維業(yè)務場景的解決方案交流社區(qū)。該社區(qū)致力于傳播 AIOps 技術,旨在與各行業(yè)客戶、用戶、研究者和開發(fā)者們共同解決智能運維行業(yè)技術難題,推動 AIOps 技術在企業(yè)中落地,建設健康共贏的AIOps 開發(fā)者生態(tài)。
智能運維領域的數據特點
指標數據作為運維場景中的重要觀測項,是服務可用性監(jiān)控、系統健康度度量等場景的主要數據來源。從下面架構示意圖中們可以看出,采集器采集服務器上各種指標數據,發(fā)往消息隊列,通過實時流處理和離線計算最終存入到數據庫。
在這個上述場景中,我們往往會遇到以下幾種數據挑戰(zhàn):
3)在數據傳輸過程中,由于受到網絡、設備資源等原因造成短時間內出現亂序到達、缺丟點、峰谷潮、重復數據等問題
4)由于服務器或設備本身原因,采集的指標數據時間往往不夠精準,導致數據粒度不齊整的問題。例如對于秒級別的指標,上一個采集的數據點的時間戳是2021-01-01 10:00:00:000下一個數據點的有可能是2021-01-01 10:00:01:015。而不同的指標相同時刻采集的數據點時間戳分別是2021-01-01 10:00:00:000和2021-01-01 10:00:00:015。
至此整體的需求基本已經明確,在做數據庫選型時需要滿足以下需求:
1)支持數據長時間存儲;
2)支持大時間跨度的快速檢索;
3)高速的數據吞吐能力;
4)高效的數據壓縮比;
5)能夠有效的解決數據的亂序、缺失值、粒度不齊整以及重復數據等數據質量問題。
智能運維領域的時序數據該如何存儲
對于上述的需求我們該如何選型?是傳統的關系型數據庫,還是通用的NoSQL數據庫,亦或是專用的時序數據庫?他們能否滿足上述數據庫選型的需求?
數據如何存儲還要結合數據本身的特點。這里以一個真實場景中的案例,某運營商有約3000萬的監(jiān)控指標,并且采集的過程中存在空值數據、數據缺失、數據重復等情況,甚至會出現新的指標。如果一分鐘采集一次指標在允許一定數據延遲的情況下,寫入速率要超過50w/s,一天需要存儲432億的數據,這對關系數據庫來說無論是從寫入速率是在查詢時效都很難滿足需求。
再看看通用的NoSQL數據庫,首先先簡單梳理一下這些指標數據的特點,我們發(fā)現這些指標數據除了有時間戳和指標值外還會有一些tag 來標識數據來自那臺機器,通過采集器實際的采集數據的樣例如下圖所示:
在通用的NoSql 數據庫雖然可以滿足吞吐量性能以及查詢性能,但是為了滿足指標的動態(tài)變更我們只能按照一個設備一張表或者多個設備共享一張表的建模方式如下圖所示。
無論是一個設備一張表還是多個設備共享一張表的存儲方式,為了能夠區(qū)分數據來哪個指標,我們只能把tags作為一列進行存儲,不難發(fā)現這種這樣建表方式會出現大量的tag數據冗余存儲的問題。并且通用的NoSql數據庫往往在解決數據重復的問題上并不友好,更多的是依靠一些排重策略來實現。排重策略通常有兩種:一種是依靠外部的排重方式達到存儲時數據已經排重,另一種是存儲不排除查詢時依靠sql來做排重。如果使用第一種數據排重無疑會增加系統的復雜度,如果使用第二種這會導致在處理過程的出現數據冗余存儲的情況。而且通用的NoSql數據庫還存在一個問題就是:沒有原生操作支持粒度卡齊或者線性填充來解決數據質量差的問題。
然而我們上面的遇到的一些數據挑戰(zhàn)實際是屬于時序數據庫要解決的典型問題,市面上也有許多優(yōu)秀的時序數據庫,例如InfluxDB、Apache IoTDB等,它們在高吞吐、低延時查詢、數據去重、數據填充、數據降采樣、高壓縮比等功能方面皆能滿足第一章中的數據存儲需求。接下來我們來重點看下完全開源的Apache IoTDB它是如何設計的。
IoTDB的設計
IoTDB的架構
IoTDB是基于LSM-Tree(Log-Structured Merge Tree)的架構進行設計的列式存儲數據庫,LSMtree的核心思想就是放棄部分讀的能力來換取最大的寫入能力。從下圖中IoTDB的整體架構圖中我們可以看出IoTDB主要有三部分構成:分別是數據庫引擎、存儲引擎和分析引擎。
數據庫引擎主要是負責sql語句的解析、數據寫入、數據查詢、數據刪除等功能。
存儲引擎主要是由TsFile來組成也是IoTDB的最具特色的設計,它不僅可以為IoTDB存儲引擎使用,而且還可以直接通過鏈接器供分析引擎使用,同時還對外開放了TsFile的API,用戶也可以自己直接通過API來獲取里面的內容。
分析引擎主要是用于與開源的數據處理平臺對接等。
IoTDB的數據讀寫流程
上面提到了IoTDB是基于LSM-Tree的思想來實現的,從以下數據寫入流程圖中我們可以看出:數據經過time detector時會根據內存中維護的最大時間戳來判斷是否數據有序,在內存緩沖區(qū)memtable中分為有序序列和亂序序列,同時為了保障在斷電后數據不丟失,IoTDB也會把數據寫入到WAL(Write-Ahead Logging)中,到此客戶端的數據寫入就已經完成。隨著數據的不斷寫入,memtable中的數據達到一定的程度后,IoTDB通過submit flush task把memtable變成Immutable最終刷到磁盤變成Sstable即TsFile文件,同時當持久化的TsFile文件達到一定程度會觸發(fā)合并。
上面介紹了IoTDB數據的寫入流程后,我們再來看下IoTDB核心的查詢流程。如下圖所示,當客戶端發(fā)送查詢請求時,首先通過Antlr4進行sql 解析,然后去內存中的MemTable、ImmuTable和硬盤中TsFile中進行查詢。當然,IoTDB這里會通過BloomFilter 和索引來提高數據的查詢效率。我們知道BloomFilter的原理是哈希結果不存在那么一定沒有此數據,如果哈希結果存在,IoTDB那么還需要繼續(xù)借助索引進行進一步的查找。
TsFile結構
上一節(jié)IoTDB的讀寫流程都離不開TsFile,那我們看看IoTDB最核心TsFile是怎樣一個結構。從下面的TsFile 結構示意圖中可以看出TsFile整體分為兩部分:一部分是數據區(qū),另一部分是索引區(qū)。
數據區(qū)主要包括Page 數據頁、Chunk數據塊和ChunkGroup數據組。其中Page 由一個?PageHeader?和一段數據(time-value 編碼的鍵值對)組成,Chunk數據塊由多個Page和一個Chunk Header組成,ChunkGroup?存儲了一個實體(Entity) 一段時間的數據,它由若干個?Chunk, 一個字節(jié)的分隔符?0x00?和一個ChunkFooter組成。
索引區(qū)主要包括TimeseriesIndex、IndexOfTimeseriesIndex和BloomFilter,其中TimeseriesIndex包含1個頭信息和數據塊索引(ChunkIndex)列表,頭信息記錄文件內某條時間序列的數據類型、統計信息(最大最小時間戳等);數據塊索引列表記錄該序列各Chunk在文件中的 offset,并記錄相關統計信息(最大最小時間戳等);IndexOfTimeseriesIndex用于索引各TimeseriesIndex在文件中的 offset;BloomFilter針對實體(Entity)的布隆過濾器。下圖中TsFile包括兩個實體 d1、d2,每個實體分別包含三個物理量 s1、s2、s3,共 6 個時間序列,每個時間序列包含兩個 Chunk。
TsFile索引構建
TsFile中所有的索引節(jié)點構成一棵類B+樹結構的多叉索引樹,這棵樹由兩部分組成:實體索引部分和物理量索引部分。下面舉一個例子來展示索引樹的構成:假設我們設置樹的度為10,我們有150個設備每個設備有150個測點共計22500條時間序列,這時我們需構建一個深度為6的索引樹即可,這時我們查詢數據所在位置需做6次磁盤的IO,具體如下圖所示。
上面這種方式看似磁盤IO次數比較多,這是由于我們設置的樹的度比較小從而導致整體樹的深度比較大。如果我們把樹的度增大到300,在實體索引部分一個高度為2的子樹即可實現90000個設備存儲,同理一個高度為2個物理量索引部分也可存放90000個物理量,最終形成的整個索引樹可存放81億條時間序列。這時我們再讀取數據只需要做4次磁盤IO即可定位到我們需要的數據位置。
TsFile查詢流程
在了解了TsFile的結構以及索引的構建,那么IoTDB是如何在TsFile內部完成一次查詢的,下面用一個具體查詢例如select s1 from root.ln.d1 where time>100 and time<200,來演示在TsFile中是如何定位到所需數據。他的具體步驟以及示意圖如下所示:
1)讀取TsFile MetadataSize信息
2)根據TsFile MetadataSize和offset獲取TsFile MetaData的位置
3)讀取Metadata IndexNode中的數據,通過MetadataIndexEntry中的name定位到設備root.ln.d1
4)讀取到設備root.ln.d1中的offset偏移量,根據偏移量找到TimeSeries Metadata 中的信息進而找到s1
5)通過ChunkMetadata記錄的統計信息startTime和endTime與我們查詢的區(qū)間(100,200)對比獲取到root.ln.d1設備下面測點s1的偏移量
6)根據s1中的偏移量可以直接獲取到ChunkGroup
7)依次通過ChunkGroupHeader、ChunkHeader定位到Chunk數據依次讀取Page中的PageHeader,如果時間區(qū)間在(100,200)中那么我們就直接讀取PageData數據。
總結
本文拋磚引玉簡單的介紹了IoTDB的讀寫以及TsFile的核心文件的設計,實際上IoTDB整體設計和實現還是比較雜,里面涉及了很多的細節(jié)這里就不再展開介紹了。
寫在最后
近年來,在AIOps領域快速發(fā)展的背景下,IT工具、平臺能力、解決方案、AI場景及可用數據集的迫切需求在各行業(yè)迸發(fā)。基于此,云智慧在2021年8月發(fā)布了AIOps社區(qū), 旨在樹起一面開源旗幟,為各行業(yè)客戶、用戶、研究者和開發(fā)者們構建活躍的用戶及開發(fā)者社區(qū),共同貢獻及解決行業(yè)難題、促進該領域技術發(fā)展。
社區(qū)先后 開源 了數據可視化編排平臺-FlyFish、運維管理平臺 OMP 、云服務管理平臺-摩爾平臺、 Hours 算法等產品。
可視化編排平臺-FlyFish:
項目介紹:https://www.cloudwise.ai/flyFish.html
Github地址: https://github.com/CloudWise-OpenSource/FlyFish
Gitee地址: https://gitee.com/CloudWise/fly-fish
行業(yè)案例:https://www.bilibili.com/video/BV1z44y1n77Y/
部分大屏案例:
總結
以上是生活随笔為你收集整理的清华自研时间序列数据库Apache IoTDB原理解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运算放大器---功耗(Iq需求)
- 下一篇: LayUI数据表格操作栏,根据数据条件改