OpenMetric與時序資料庫模型之主流TSDB分析
摘要:為大家帶來當下時序資料模型的主流TSDB分析及雲廠商在時序資料模型方面的最新動態。
本文分享自華為雲社群《【萬字乾貨】OpenMetric與時序資料庫儲存模型分析(下)》,作者:敏捷的小智 。
在上篇《【萬字乾貨】OpenMetric與時序資料庫儲存模型分析(上)》文章中,我們瞭解了時序資料模型的相關知識內容,接下來為大家分析當下主流TSDB及雲廠商在書序資料模型方面的最新動態。
主流TSDB分析
InfluxDB
InfluxDB[9]是一個一站式的時序工具箱,包括了時序平臺所需的一切:多租戶時序資料庫、UI和儀表板工具、後臺處理和監控資料採集器。如下圖9所示。
圖9
InfluxDB支援動態shcema,也就是在寫入資料之前,不需要做schema定義。因此,使用者可以隨意新增measurement、tag和field,可以是任意數量的列。
InfluxDB底層的儲存引擎經歷了從LevelDB到BlotDB,再到自研TSM的歷程。從v1.3起,採用的是基於自研的WAL + TSMFile + TSIFile方案,即所謂的TSM(Time-Structured Merge Tree)引擎。其思想類似LSM,針對時序資料的特性做了一些特殊優化。TSM的設計目標一是解決LevelDB的檔案控制代碼過多問題,二是解決BoltDB的寫入效能問題。
Cache: TSM的Cache與LSM的MemoryTable類似,其內部的資料為WAL中未持久化到TSM File的資料。若程序故障failover,則快取中的資料會根據WAL中的資料進行重建。
WAL(Write Ahead Log) : 時序資料寫入記憶體之後按照SeriesKey進行組織。資料會先寫入WAL,再寫入memory-index和cache,最後刷盤,以保證資料完整性和可用性。基本流程包括:根據Measurement和TagKV拼接出乎series key;檢查該series key是否存在;如果存在,就直接將時序資料寫入WAL、時序資料寫快取;如果不存在,就會在Index WAL中寫入一組entry;依據series key所包含的要素在記憶體中構建倒排索引、接著把時序資料寫入WAL和快取。
TSM Files: TSM File與LSM的SSTable類似。在檔案系統層面,每一個TSMFile對應了一個 Shard,單個最大2GB。一個TSM File中,有存放時序資料(i.e Timestamp + Field value)的資料區,有存放Serieskey和Field Name資訊的索引區。基於 Serieskey + Fieldkey構建的形似B+tree的檔案內索引,通過它就能快速定位到時序資料所在的資料塊。在TSMFile中,索引塊是按照 Serieskey + Fieldkey 排序 後組織在一起的。
TSI Files:使用者如果沒有按預期根據Series key來指定查詢條件,比如指定了更加複雜的查詢條件,技術手段上通常是採用倒排索引來確保它的查詢效能的。由於使用者的時間線規模會變得很大,會造成倒排索引消耗過多的記憶體。對此InfluxDB引入了TSIfiles。TSIFile的整體儲存機制與TSMFile相似,也是以 Shard 為單位生成一個TSIFile。
在InfluxDB中有一個對標傳統RDB的Database概念。邏輯上每個Database下面可以有多個measurement。在單機版中每個Database實際對應了一個檔案系統的目錄。
InfluxDB作為時序資料庫,必然包括時序資料儲存和一個用於度量、標記和欄位元資料的倒排索引,以提供更快速的多維查詢。InfluxDB在TSMFile上按照下面的步驟掃描資料,以獲得高效能查詢效果:
• 根據使用者指定的時間線(Serieskey)和FieldKey在索引區找到Serieskey+FieldKey所在的 索引資料塊。
• 根據使用者指定的時間戳範圍在索引資料塊中查詢資料對應在哪個或哪幾個索引條目
• 把檢索出的索引條目所對應的時序資料塊載入到記憶體中進一步掃描獲得結果
和 Prometheus 一樣,InfluxDB 資料模型有鍵值對作為標籤,稱為標籤。InfluxDB 支援解析度高達納秒的時間戳,以及 float64、int64、bool 和 string 資料型別。相比之下,Prometheus 支援 float64 資料型別,但對字串和毫秒解析度時間戳的支援有限。InfluxDB 使用日誌結構合併樹的變體來儲存帶有預寫日誌,按時間分片。這比 Prometheus 的每個時間序列的僅附加檔案方法更適合事件記錄。
Prometheus
下圖是Prometheus官方架構圖[10],包括了一部分生態元件,它們大多是可選項。其中最核心的是Prometheus 伺服器,它負責抓取和儲存時間序列資料,並對這些資料應用規則,從而聚合出新的時間序列或生成警報,並記錄儲存它們。
圖10
TSDB是Prometheus的關鍵核心引擎。最新的V3引擎[7]相當於面向TSDB場景優化後的LSM(Log Structured Merge Tree,結構化合並樹)。LSM樹核心思想的核心就是放棄部分讀能力,換取寫入的最大化能力;其假設前提就是記憶體足夠大。通常LSM-tree適用於索引插入比檢索更頻繁的應用系統。V3儲存引擎也採用了Gorilla論文思想。它包括了下面幾個TSDB元件:塊頭(Head Block)、預寫日誌WAL及檢查點、磁碟上Chunk頭的記憶體對映、持久化block及其索引和查詢模組。下圖11是Prometheus的磁碟目錄結構。
圖11
在V3引擎中一個chunk內會包含很多的時間線(Time series)。Chunk目錄下的樣本資料分組為一個或者多個段(segment),每個預設不超過512MB。index是這個block下的chunk目錄中的時間線按照指標名稱和標籤進行索引,從而支援根據某個label快速定位到時間線以及資料所在的chunk。meta.json是一個簡單的關於block資料和狀態的一個描述檔案。Chunks_head負責對chunk索引,uint64索引值由檔案內偏移量(下4個位元組)和段序列號(上4個位元組)組成。
Prometheus將資料按時間維度切分為多個block。只有最近的一個block允許接收新資料。最新的block要寫入資料,會先寫到一個記憶體結構中,為了保證資料不丟失,會先寫一份預寫日誌檔案WAL,按段(大小128MB )儲存在目錄中。它們是未壓縮的原始資料,因此檔案大小明顯大於常規塊檔案。Prometheus 將保留三個或者多個WAL檔案,以便保留至少兩個小時的原始資料。
V3引擎將2個小時作為塊(block)的預設塊持續時間;也就是塊按2h跨度來分割(這是個經驗值)。V3也是採用了LSM一樣的compaction策略來做查詢優化,把小的block合併為大的block。對於最新的還在寫資料的block,V3引擎則會把所有的索引全部hold在記憶體,維護一個記憶體結構,等到該block關閉再持久化到檔案。針對記憶體熱資料查詢,效率非常高。
Prometheus官方再三強調了它的本地儲存並不是為了持久的長期儲存;外部解決方案提供延長的保留時間和資料永續性。社群有多種整合方式嘗試解決這個問題。比如Cassandra、DynamoDB等。
通過指標實現應用的可觀察性(observability)是IT監控運維繫統的第一步。指標提供彙總檢視,再結合日誌提供的有關每個請求或事件的明細資訊。這樣更容易幫助問題的發現與診斷。
Prometheus 伺服器彼此獨立執行,僅依賴其本地儲存來實現其核心功能:抓取、規則處理和警報。也就是說,它不是面向分散式叢集的;或者說當前它的分散式叢集能力是不夠強大的。社群的Cortex、Thanos等開源專案就是針對Prometheus的不足而湧現出來的成功解決方案。
Druid
Druid[11]是有名的實時OLAP分析引擎。Druid的架構設計比較簡潔(如下圖12)。叢集中節點分3類:Master節點、Query節點和Data節點。
圖12
Druid資料儲存在datasource中,類似於傳統RDBMS中的表(table)。每個datasource都按時間(其他屬性也可以)分割槽(partition)。每個時間範圍稱為一個“塊(Chunk)”(例如,一天,如果您的資料來源按天分割槽)。在一個Chunk內,資料被分成一個或多個 “段(Segment)”。每個段都是一個檔案,通常包含多達幾百萬行資料。如下圖13所示。
圖13
Segment的目的在於生成緊湊且支援快速查詢的資料檔案。這些資料在實時節點MiddleManager上產生,而且可變的且未提交的。在這個階段,主要包括了列式儲存、bitmap索引、各種演算法進行壓縮等。這些Segment(熱資料)會被定期提交和釋出;然後被寫入到DeepStorage(可以是本地磁碟、AWS的S3,華為雲的OBS等)中。Druid與HBase類似也採用了LSM結構,資料先寫入記憶體再flush到資料檔案。Druid編碼是區域性編碼,是檔案級別的。這樣可以有效減小大資料集合對記憶體的巨大壓力。這些Segment資料一方面被MiddleManager節點刪除,一方面被歷史節點(Historical)載入。與此同時,這些Segment的條目也被寫入元資料(Metadata)儲存。Segment的自描述元資料包括了段的架構、其大小及其在深度儲存中的位置等內容。這些元資料被協調器(Coordinator)用來進行查詢路由的。
Druid 將其索引儲存在按時間分割槽的Segment檔案中。Segment檔案大小推薦在 300MB-700MB 範圍內。Segment檔案的內部結構,它本質上是列存的:每一列的資料被佈置在單獨的資料結構中。通過單獨儲存每一列,Druid 可以通過僅掃描查詢實際需要的那些列來減少查詢延遲。共有三種基本列型別:時間戳列、維度列和指標列,如下圖14所示:
圖14
維度(Dimension)列需要支援過濾和分組操作,所以每個維度都需要以下三種資料結構:
1) 將值(始終被視為字串)對映到整數 ID 的字典,
2) 列值的列表,使用 1 中的字典編碼。 【服務於group by和TopN查詢】
3) 對於列中的每個不同值,一個指示哪些行包含該值的點陣圖(本質就是倒排索引,inverted index)。【服務於快速過濾,方便AND和OR運算】
Druid中每列儲存包括兩部分:Jackson 序列化的 ColumnDescriptor和該列的其餘二進位制檔案。 Druid強烈推薦預設使用LZ4壓縮字串、long、float 和 double 列的值塊,使用Roaring壓縮字串列和數字空值的點陣圖。尤其在高基數列場景中匹配大量值的過濾器上Roaring 壓縮演算法要快得多(對比CONCISE 壓縮演算法)。
值得一提的是Druid支援Kafka Indexing Service外掛(extension),實現實時攝入(ingestion)任務,那麼此時可以立即查詢該segment,儘管該segment並沒有釋出(publish)。這更能滿足對資料的產生到可查詢可聚合分析的實時性要求。
Druid另外一個重要特性就是在資料寫入的時候,可以開啟rollup功能,將選定的所有dimensions 按照你指定的最小時間間隔粒度(比如1分鐘,或者5分鐘等)進行聚合。這樣可以極大的減少需要儲存的資料大小,缺點是原始的每條資料就被丟棄了,不能進行明細查詢了。
Druid為了讓查詢更高效,有如下設計考慮。
• Broker修剪每個查詢訪問哪些Segment:它是 Druid 限制每個查詢必須掃描的資料量的重要方式。首先查詢先進入Broker,Broker 將識別哪些段具有可能與該查詢有關的資料。然後,Broker 將識別哪些Historian和 MiddleManager正在為這些段提供服務,並向這些程序中的每一個傳送重寫的子查詢。Historical/MiddleManager 程序將接收查詢、處理它們並返回結果。Broker 接收結果並將它們合併在一起以獲得最終答案,並將其返回給原始呼叫者。
• Segment內利用索引過濾:每個Segment內的索引結構允許 Druid 在檢視任何資料行之前確定哪些(如果有)行與過濾器集匹配。
• Segment內只讀取特定關聯的行和列:一旦 Druid 知道哪些行與特定查詢匹配,它只會訪問該查詢所需的特定列。在這些列中,Druid可以從一行跳到另一行,避免讀取與查詢過濾器不匹配的資料。
時間戳也是Druid資料模型的必備項。儘管Druid不是時序資料庫,但它也是儲存時序資料的自然選擇。Druid資料模型可以支援在同一個datasource中,可以同時存放時序資料和非時序資料。因此,Druid不認為資料點是“時間序列”的一部分,而是將每個點單獨處理以進行攝入和聚合。比如正統的TSDB支援的時序資料插值計算,在Druid中就不復存在的必要了。這會給一些業務場景的處理帶來很大的便利性。
IoTDB
Apache IoTDB[12] 始於清華大學軟體學院,2020年9月為 Apache 孵化器專案。IoTDB 是一個用於管理大量時間序列資料的資料庫,它採用了列式儲存、資料編碼、預計算和索引技術,具有類 SQL 的介面,可支援每秒每節點寫入數百萬資料點,可以秒級獲得超過數萬億個資料點的查詢結果。主要面向工業界的IoT場景。
IoTDB 套件由若干個元件構成,共同形成資料收集、資料攝入、資料儲存、資料查詢、資料視覺化、資料分析等一系列功能。如下圖15所示:
圖15
IoTDB 特指其中的時間序列資料庫引擎;其設計以裝置、感測器為核心,為了方便管理和使用時序資料,增加了儲存組(storage group的概念)。
儲存組(Storage Group): IoTDB提出的概念,類似於關係資料庫中的Database的概念。一個儲存組中的所有實體的資料會儲存在同一個資料夾下,不同儲存組的實體資料會儲存在磁碟的不同資料夾下,從而實現物理隔離。對IoTDB內部實現而言,儲存組是一個併發控制和磁碟隔離的單位,多個儲存組可以並行讀寫。對使用者而言,方便了對裝置資料的分組管理和方便使用。
裝置 (Device):對應現實世界中的具體物理裝置,比如飛機發動機等。在IoTDB中, device是時序資料一次寫入的單位,一次寫入請求侷限在一個裝置中。
感測器(Sensor): 對應現實世界中的具體物理裝置自身攜帶的感測器,例如:風力發電機裝置上的風速、轉向角、發電量等資訊採集的感測器。在IoTDB中,Sensor也稱為測點(Measurement)。
測點/物理量(Measurement,也稱工況、欄位 field):一元或多元物理量,是在實際場景中感測器採集的某時刻的測量數值,在IoTDB內部採用<time, value>的形式進行列式儲存。 IoTDB儲存的所有資料及路徑,都是以測點為單位進行組織。測量還可以包含多個分量(SubMeasurement),比如GPS 是一個多元物理量,包含 3 個分量:經度、維度、海拔。多元測點通常被同時採集,共享時間列。
IoTDB的儲存由不同的儲存組構成。每個儲存組是一個併發控制和資源隔離單位。每個儲存組裡麵包括了多個Time Partition。其中,每個儲存組對應一個WAL預寫日誌檔案和TsFile時序資料儲存檔案。每個Time Partition中的時序資料先寫入Memtable,同時記入WAL,定時非同步刷盤到TsFile。這就是所謂的tLSM時序處理演算法。
攝入效能方面:IoTDB 具有最小的寫入延遲。批處理大小越大,IoTDB 的寫入吞吐量就越高。這表明 IoTDB 最適合批處理資料寫入方案。在高併發方案中,IoTDB 也可以保持吞吐量的穩定增長(受網絡卡、網路頻寬約束)。
聚合查詢效能方面:在原始資料查詢中,隨著查詢範圍的擴大,IoTDB 的優勢開始顯現。因為資料塊的粒度更大,列式儲存的優勢體現出來,所以基於列的壓縮和列迭代器都將加速查詢。在聚合查詢中,IoTDB使用檔案層的統計資訊並快取統計資訊。多個查詢只需要執行記憶體計算,聚合效能優勢明顯。
資料儲存對比
基於前面的分析,我們嘗試用下面的表格對比來說明這些時序資料處理系統的特點。
表3
對於時序資料的處理,關鍵能力主要包括資料模型定義、儲存引擎、與儲存緊密協作的查詢引擎和支援分割槽擴充套件的架構設計。主流的TSDB基本都是基於LSM或者結合時序資料場景專門優化的LSM tree來實現(包括InfluxDB號稱的TSM,IoTDB的tLSM,本質上都還是LSM機制)。其中只有IoTDB獨創採用了tree schema來對時序資料建模。為了追求極致效能和極致成本,大家都在針對海量資料和使用場景,持續改進和優化資料的儲存結構設計、各種高效索引機制、和查詢效率。從單點技術或者關鍵技術上來講,有趨同性和同質化的大趨勢。
雲廠商最新動態
除了開源社群推陳出新外,國內外眾多雲服務廠商也陸續釋出了相關的時序資料庫產品或者服務。
華為雲
華為雲的GaussDB for Influx[13]雲服務,基於InfluxDB進行深度優化改造,在架構、效能和資料壓縮等方面進行了技術創新,取得了很好的效果。實現了儲存與計算分離架構,其中採用了華為雲自研的高效能分散式儲存系統,顯著提升了時序資料庫的可靠性;同時方便計算節點分鐘級擴容和儲存空間的秒級擴容,同時大幅降低儲存成本。支援億級時間線(開源的能力在千萬時間線級別),寫入效能基本保持穩定;能夠支援更高的高雜湊聚合查詢效能;在壓縮演算法上,相比原生的InfluxDB,重點針對Float、String、Timestamp這三種資料型別進行了優化和改進。。
華為雲MRS雲服務包含了IoTDB[14],其中 IoTDB定位為面向工業裝置、工業現場的時序資料庫庫。IoTDB優化後效能更好,千萬級資料點秒級寫入,TB級資料毫秒級查詢;優化後的資料壓縮比可達百倍,進一步節省儲存空間和成本;通過採用對等分散式架構,雙層多Raft協議,邊雲節點同步雙活,做到7*24小時高可用。在工業化場景,真正做到一份時序資料相容全場景、一套時序引擎打通雲邊端和一套框架整合雲邊端。
阿里雲
據公開資料[15],阿里雲時序時空資料庫TSDB的發展演變經歷了三個階段。在v1.0階段基於OpenTSDB,底層實現了雙引擎——HBase和HiStore。在v2.0階段中,把OpenTSDB引擎換成了自研的TSDB引擎,彌補了OpenTSDB不支援的倒排索引、面向時序場景的特殊編碼、分散式流計算聚合函式等特性。隨後實現了雲和邊緣計算一體化,TSQL相容Prometheus生態。其中TSDB for Spatial Temporal支援時空資料,它基於自研的S3時空索引和高效能電子圍欄。最新TSDB同樣基於 Gorilla, 將單個數據點的平均使用儲存空間降為1~2個位元組,可以降低90%儲存使用空間,同時加快資料寫入的速度。對於百萬資料點的讀取,響應時間小於 5 秒,且最高可以支撐每秒千萬資料點的寫入。相較於開源的 OpenTSDB 和 InfluxDB,讀寫效率提升了數倍,同時相容 OpenTSDB 資料訪問協議。
騰訊雲
騰訊雲也推出了TencentDB for CTSDB[16]雲服務,它是一款分散式、可擴充套件、支援近實時資料搜尋與分析的時序資料庫,相容 Elasticsearch 常用的 API 介面和生態。它支撐了騰訊內部20多個核心業務。效能方面可以做到每秒千萬級資料點寫入,億級資料秒級分析。CTSDB也是採用LSM機制,先寫記憶體再週期性刷寫到儲存;然後通過倒排索引加速任意維度資料查詢,能實現資料秒級可查。也支援像histogram、percentile、cardinality這樣的通用聚合計算函式;也通過配置 Rollup 任務定時聚合歷史資料儲存至新的資料表,實現降精度(Downsampling)特性。在叢集中節點數量超過30個時,需要新購叢集或者將通用叢集架構優化升級為混合節點叢集架構,以保證多節點超大叢集的效能穩定。從這些特性推斷,CTSDB核心應該是借鑑了ElasticSearch核心深度優化經驗的基礎上構建的時序資料庫能力。
國內其他廠商
除了雲服務廠商提供的開箱即用的雲服務外,還有一些創新型產品湧現出來,比較有名的包括TDengine[17]、位元組跳動的TerarkDB[18]、DolphinDB[19]等等。他們也在快速演進發展中,值得大家持續跟蹤關注,尤其是國內孵化出來的一些TSDB產品。
總結與展望
InfluxDB、IoTDB和OpenTSDB等除了社群版本外,也有云廠商提供原生InfluxDB(阿里雲TSDB for InfluxDB)、IoTDB(華為雲MRS IoTDB)或OpenTSDB(華為雲MRS OpenTSDB)雲化服務,方便使用。更主流的做法是各雲廠商根據自身的技術沉澱和研發實力,借鑑、優化甚至重新研發了時序資料庫核心,能提供更強的叢集能力,更高效能寫入,更快的查詢和聚合分析能力。國外廠商AWS有Timestream[20],一種Serverless時序資料庫服務,國內華為雲的GaussDB for Influx,匯聚頂級資料庫專家團隊打造的新一代時空分析資料庫;騰訊雲的TencentDB for CTSDB,相容ES生態;阿里雲的HiTSDB等等。這些開箱即用的、可擴充套件的、高可用的時序資料庫,為雲原生應用的開發與部署帶來了福音,無需管理底層基礎設施,只需專注於業務構建。
Promeheus發展過程中,其需要長期儲存的歷史資料(long-term)儲存是其短板之一。業界有一些折中的整合方案。比如採用Cassandra作為Prometheus的持久化儲存;還有采用InfluxDB作為Prometheus的持久化儲存,一方面充分利用Prometheus監控相關能力和社群生態(包括支援分散式叢集的Cortex);另一方面利用好InfluxDB時序資料庫優點,尤其是超PB級的分散式資料庫能力,以彌補Prometheus在海量歷史資料儲存上的短板。
Apache Druid在OLAP即時分析領域有著很強的競爭力,也為眾多大廠所採用。業界最大的叢集擁有4000多個節點。不管是時序指標,還是業務資料,應用日誌等,都可以利用Druid的Kafka Indexing Service和其強大的資料預處理能力,轉換為時序資料進入Druid。目前Druid SQL特性發展也很快,包括跨表join,subquery和眾多函式、運算元的持續豐富。
不管是正統的時序資料庫,還是適合時序資料的OLAP分析系統;不管是開源社群的熱門專案,還是雲廠商提供更強大的雲原生時序資料庫,都為各種時序資料(包括指標、業務資料)的儲存、檢索和分析提供多樣化的選擇。使用者結合自己的業務場景,一定能找到相對適合的工具或服務,滿足業務訴求。
參考資料
[9]https://www.influxdata.com/products/influxdb/
[10]https://prometheus.io/docs/introduction/overview/
[11]https://druid.apache.org/docs/latest/design/architecture.html
[12]https://iotdb.apache.org/SystemDesign/Architecture/Architecture.html
[13]https://bbs.huaweicloud.com/blogs/252115
[14]https://bbs.huaweicloud.com/blogs/280948
[15]https://developer.aliyun.com/article/692580
[16]https://cloud.tencent.com/developer/article/1010045
[17]https://www.taosdata.com/cn/
[18]https://github.com/bytedance/terarkdb
[19]https://www.dolphindb.cn/
[20]https://aws.amazon.com/cn/timestream