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