您好,登錄后才能下訂單哦!
本篇內容主要講解“時序數據庫ModelarDB實例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“時序數據庫ModelarDB實例分析”吧!
問題背景
工業系統(如風機)產生的數據量太大,無法存儲所有原始數據,現在普遍只存儲了聚合信息。但是這樣會丟失原始數據中的波動和異常值,但是通常這些信息是很寶貴的,可以用來做故障診斷。
時序數據庫需要具有的重要性質:分布式,流處理(寫入即可見),高壓縮,高效檢索,模糊查詢處理AQP(Approximate Query Processing),可擴展性(不需要修改代碼就能增加領域知識)。
時間序列
時間序列(Time Series):一系列有時間和值的二元組,并且時間維度遞增。
比如:(100,28.3)(200,30.7)(300,28.3)(400,28.3)(500,15.2)...
一個有有限個數據點的時間序列叫有界時間序列。
定頻時間序列(Regular Time Series):相鄰兩個時間點的時間間隔相等。
上邊那個就是定頻的。
采樣間隔(Sampling Interval):定頻時間序列中兩個相鄰時間點的時間間隔。
上邊那個間隔就是 100。
模型
上邊的概念沒啥新奇的,重點在模型,這篇文章主要要理解模型是什么:
模型(model):是一個時間序列的表示,包括兩個函數(Mest,Merr),第一個函數輸入一個時間點,給出一個估計的值。第二個函數輸入一個時間序列和第一個函數,給出一個正實數,作為誤差估計。
以上邊那個包含 5 個點時間序列為例,可以給一個模型:
Mest = -0.0024 * ti + 29.5, 1 ≤ i ≤ 5
Merr = max( |vi - Mest(ti)| ), 1 ≤ i ≤ 5
這里 vi 和 ti 就是從原始的時間序列得到的。其實就是用一個一次函數用來估計值,計算每個點的絕對誤差,保留最大的那個。
這個模型沒問題,但是起碼在計算 Merr 時還需要原始時間序列。
間斷(GAP):就是一個時間段(ts,te),用來表示一個數據源產生的兩段相同采樣間隔的定頻時間序列中間的間斷大小,其中 te = ts + m*采樣間隔,m大于等于2,也就是至少需要缺一個點,因為一個都不缺時 m 就為1。
像(100,x)(200,x)(400,x)中間就有間斷,就是不定頻的時間序列。
將不定頻的時間序列的GAP用空值填上,就變成了帶間斷的定頻時間序列。
段(Segment):一個段就是一個有界的帶間斷的定頻時間序列,包括幾個元素:起始時間,終止時間,采樣間隔,空值時間點的集合,模型,誤差。
這個 segment 就是最終 boss 了,前邊推了那么多就是為了引出 segment,之后系統存儲的也是 segment。ModelarDB 只適用于定頻時間序列,這是硬傷。
一個有5個點的時間序列,假如第5個點不符合用戶定義的錯誤率,就把前四個用 segment 表示,第五個點等接下來的數據來了之后再創建 segment,如下圖示例:
系統架構
說是一個系統,其實是一個 jar 包,這個 jar 包依賴了 Spark 、Spark-Cassandra-Connector 和 Cassandra,實現了他們的接口。
ModelarDB 的架構圖如下圖,基本包括數據導入模塊(生成segment),查詢接口,存儲接口,還有一個元數據 cache 模塊。
這張圖說每個 ModelarDB 節點上都有一個 Spark 節點和 Cassandra,保證數據本地性,其實任意一個使用 Spark-Cassandra-Connector 的客戶端都能做到這個。
數據流動:通過 segment 生成器給時間序列數據做個轉換,選擇合適的模型,生成一堆 segment,然后 cache 在內存里,并把舊的 segment 持久化到 Cassandra 里。內存里的和 Cassandra 里的都可以查詢。
為啥選 Spark 和 Cassandra?因為都是成熟的分布式系統,天生自帶高可用的特性,而且好集成,有現成的擴展接口。這里還提到了一個 Simba 系統,也是基于 Spark 做的一個用來管理時空數據的,跟 ModelarDB 的原理差不多。
使用方式
查詢:只需要把 ModelarDB 的 jar 包提交成一個 Spark 作業,Spark 會自動分發 jar 包并行執行,看起來就是分布式時序數據查詢。
導入:可以直接 java -jar 啟動主函數,里邊會自動啟動 SparkSession,用 spark local 模式往 Cassandra 里寫數據。
容錯
作者討論了一下容錯機制,因為集成的現有分布式系統,所以只在系統架構層面考慮,不會考慮細節的東西,比如 Cassandra 里一個節點掛了會怎樣。
出錯只有三種情況:(1)數據導入時(2)內存中的數據(3)磁盤上的數據。這三種情況分別有不同的解決策略。
(1)第一種是將數據緩存在 kafka 中,這樣導入時候 ModelarDB 掛了,數據在 kafka 里還有。雖然解法很雞賊,跟 ModelarDB 沒啥關系,但是確實很實用,在實際場景我也會這么選。
另一種是在多個節點并行導入(作者沒有細說,我覺得是將一份數據交給多個節點同時解析,由于 key 相同,最后只會留一份),但是這種會很費資源,沒必要。
(2)(3)利用 Spark 和 Cassandra 自帶的副本保證安全。Cassandra 的副本可以理解,畢竟是個數據庫,Spark 有啥副本?個人覺得是 Spark 的 RDD 的容錯機制,一個 RDD 壞了重新從源頭算出來。
并且為了保證導入速度,最后作者采用了單節點導入數據,允許丟失一部分。也沒用 kafka。容錯機制直接用的 Spark 和 Cassandra 的,也沒做修改。
其實只是在架構層面討論了一下容錯,實際沒額外做工作。這也是利用現有系統的好處,雖然自己沒做,但是也是系統的一部分特性。
模型壓縮示例
數據導入時候會根據時間序列的特點自動分段,生成多個 segment。論文的重點就是這部分,剩下的都是比較工程化的東西。
ModelarDB 提出的壓縮方法在高壓縮率和低延遲之間做了平衡。這里的延遲就是流處理中的時間窗口,在本文指代最大不可查點數。
舉個例子:
系統分三層,最上層是 segment 生成器,里邊有數據點的 buffer,用來接收數據點,實線是緩存的,虛線是被刪除的。這里最大延遲設置為 3 個點,也就是最多只能有最近的 2 個點不可見,當第三個點到達時,就需要創建一個臨時段(ST)放在內存里,支持查詢。
T表示內存中 segment 的最后一個點,上圖t3時候產生了一個 segment,復制到 cache 里,這時 t3 之前的點都可見了,當接收到 t4 點的時候還可以繼續加到上一個 segment 中,但是還不著急對用戶可見,所以先放著,如果當前 segment 又攢夠了 3 個點,就再更新到 cache 一次。
如果遇到了一個用戶設置的閾值外的離群點,就關閉當前 segment,更新到 cache 中,并且把 buffer 中的刪除。segment 的最后這個點為 F。
ye 是 buffer 中還沒被 segment 包含的點數。當 cache 中的 segment 達到一定大小就刷到等存儲 storage 中。
model-agnostic copression:模型無關的壓縮算法
上面的示例只有一個模型。實際算法里支持用多個模型去壓縮一個時間序列。多模型的時候,每次產生一個最終 segment 的過程如下:
每次從 TS 里拿一個點先放到 buffer里。嘗試加到第一個模型里,當新的點不能被當前模型表示時,就去嘗試用下一個模型表示 buffer 里的所有點。如果所有模型都試過了,就選擇一個壓縮率最高的模型作為最終的segment(SF)放到 cache 中。
看個示例吧,假如 buffer 里有這么幾個點,并且三個模型都試了。這里壓縮率最高的不一定是表示的點數最多的,可能 model2 壓縮率最高,于是就被刷出去了。主要是看誰吃的好,而不是看誰吃的多。
比如第一次 model2 勝出,segment1 被刷到 cache 中了,然后三個模型繼續從第四個點開始吃,這次 model3 壓縮最好,于是 segment2 又被刷出去了。這里 segment 的編號只是從 1 開始而已,跟 model id 沒關系。
這個壓縮算法是模型 agnostic 的,其實就是動態選擇最佳模型。
模型也是可擴展的,任何人都可以實現 ModelarDB 中模型的接口去擴展模型,比較靈活。
查詢模式
ModelarDB 提供兩種視圖支持查詢,第一種是段視圖(段ID, 起始時間, 終止時間, 采樣間隔, 模型ID, 模型參數),第二種是點視圖(段ID, 時間戳, 值)。這兩種視圖就是兩種表結構。sql 也得針對這兩種表結構去寫。
單點的接口最后也是實現在 segment 之上的。所以可以只考慮 segment 查詢。
優化行重組
這是個很工程的東西,用來加速行的重組的。
SparkSQL 中的查詢會選擇視圖中的一些列,交給 ModelarDB 去執行,執行完結果后還需要拼成一行一行的格式返回給 SparkSQL,這基本就是 SparkSQL 的接口。
在每次拼一行數據時,都需要根據 SparkSQL 給我的列名去一個一個找對應的值,這樣比較費勁。作者在這里提供了一個函數,這個函數接收一個數據點,直接返回一行。
如何生成這個函數呢?用點視圖舉例:(段ID, 時間戳, 值),各列下標分別是1,2,3。
首先根據點視圖和查詢的列名拿到各個列的 index 的拼接,比如我查詢的是(時間戳,值),拼接出來就是 23,(值,段ID)= 31。
針對每種組合,手動寫這個函數。因為每種視圖都不超過 10 列,而且表結構是固定的,所以這個優化方案可行,工作量也還能接受。如果表結構不固定或者行數太多這種方法就不適用了。
底層存儲
Cassandra 中表結構是這樣的,有三張表,Time Series 存儲 segment id 和 采樣間隔,Segment 表存儲 segment 的信息,model 表存儲模型信息。
一個 Time Series 可以對應很多個 segment,一個 model 也可以對應很多個 segment。可以做謂詞下推,也是利用了 Spark-Cassandra-Connector 的功能。
對比
壓縮率:用模型代替原始數據肯定能壓的很好,跟其他流行的時間序列數據庫和大數據文件格式做了對比。
寫入速度:吊打了其他系統和文件格式,這也沒的說的,畢竟 ModelarDB 沒存原始點,I/O上的優勢比較大。
局限
只支持定頻數據,感覺這一點就可以宣布死刑了。
文章開頭介紹場景時說工業場景復雜,數據可能缺失、亂序,但是后來沒有提亂序的解決方案。
針對一個時間序列,每一段都會嘗試所有的模型。也就是寫入速度和模型數成正比,候選模型多了會拖慢寫入速度,不過作者沒提這個事。
個人感覺有損壓縮是無法接受的,也沒見過實用的數據庫是有損的。
到此,相信大家對“時序數據庫ModelarDB實例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。