在時序數(shù)據(jù)庫場景下,亂序數(shù)據(jù)的定義為:“時間戳(timestamp)不按照遞增順序到達(dá)數(shù)據(jù)庫的數(shù)據(jù)?!彪m然它的定義很簡單,但時序數(shù)據(jù)庫需要有相應(yīng)的處理邏輯來保證數(shù)據(jù)存儲時的順序性,這勢必會增加數(shù)據(jù)庫架構(gòu)的復(fù)雜性,從而影響數(shù)據(jù)庫的性能表現(xiàn)。
已知完全亂序的數(shù)據(jù)處理是業(yè)界的難題,因此 TDengine 需要重點解決的問題應(yīng)該是——從實際的業(yè)務(wù)場景出發(fā),如何對偶發(fā)亂序數(shù)據(jù)的進行高效處理(比如設(shè)備損壞斷電,網(wǎng)絡(luò)異常,數(shù)據(jù)補錄等問題)。
TDengine 的數(shù)據(jù)流向是:硬盤(WAL)→ 內(nèi)存(Vnode Buffer)→ 硬盤(Data File)。
在 WAL 中,我們記錄的是數(shù)據(jù)到達(dá)數(shù)據(jù)庫的順序,但是數(shù)據(jù)入庫后,是一定要保證時間戳的有序的。因此,亂序數(shù)據(jù)的處理發(fā)生在寫入 WAL 后的兩個階段:
基于以上邏輯,我們對亂序數(shù)據(jù)分為兩類:
一. 內(nèi)存亂序數(shù)據(jù):在同一張表的范疇內(nèi),指時間戳與內(nèi)存數(shù)據(jù)的時間范圍相交的數(shù)據(jù)。
二. 硬盤亂序數(shù)據(jù):在同一張表的范疇內(nèi),指時間戳與硬盤數(shù)據(jù)的時間范圍相交的數(shù)據(jù)。
對于類型一的亂序數(shù)據(jù),TDengine 會在內(nèi)存中通過為每張表建立一個跳表結(jié)構(gòu)做好排序,從而解決問題。
場景: 創(chuàng)建某表后,我們寫入了從 1970 年到 2023 年的一小批數(shù)據(jù)(由于數(shù)據(jù)量較少不足以觸發(fā)落盤)。當(dāng)我們再寫入一條 1998 年時間戳的亂序數(shù)據(jù)時,會由跳表進行排序,排序后數(shù)據(jù)在內(nèi)存中以“1970-1998-2023”的順序有序存在。該排序操作的成本由寫入操作承擔(dān),但由于內(nèi)存中保留的只是極少數(shù)數(shù)據(jù),因此影響極小。
當(dāng)來到落盤階段時(落盤的細(xì)節(jié)可參考:文章:與 TDengine 性能直接相關(guān)——3.0 的落盤機制優(yōu)化及使用原則),這三條有序的數(shù)據(jù),又都有可能成為亂序數(shù)據(jù)的存在——即類型二:
首先,我們交代一下硬盤上數(shù)據(jù)文件的設(shè)計背景:由于 TDengine 通過建庫參數(shù) duration(days) 做數(shù)據(jù)分區(qū),假設(shè)某庫 duration 設(shè)置為 10 日,那么自打 1970 年 1 月 1 日 0 時起,每隔 10 天就會劃分一個數(shù)據(jù)文件組。寫入的數(shù)據(jù)時間戳歸屬于哪個時間范圍,便會寫入哪個數(shù)據(jù)文件組中——即每個數(shù)據(jù)文件組中都包含了固定時間范圍內(nèi)的數(shù)據(jù)。而這些數(shù)據(jù)以數(shù)據(jù)塊的形式存在,每個數(shù)據(jù)塊所包含的時間范圍視落盤時實際情況而定。
落盤時,數(shù)據(jù)會各自找到自己所屬的數(shù)據(jù)文件組,根據(jù)該數(shù)據(jù)文件組中已有的數(shù)據(jù)塊的時間范圍計算,來判斷數(shù)據(jù)的亂序與否。由此,會衍生出各種不同的情況。我們選出屬于 2023、1998、1970 年份的三條數(shù)據(jù),分別舉例三種情況:
- “2023-01-01 xxxxxxx” 這條數(shù)據(jù)落盤時,并沒有和這個表的任何數(shù)據(jù)塊的產(chǎn)生時間交集——也就是非亂序的正常數(shù)據(jù)。
- “1998-01-01 xxxxxxxx”:這條數(shù)據(jù)落盤時雖然和該表的整體時間范圍(1970–2023)產(chǎn)生交集,但是局部時間范圍內(nèi)沒有和該表任何數(shù)據(jù)塊產(chǎn)生交集。這種亂序通常發(fā)生于歷史數(shù)據(jù)的數(shù)據(jù)補錄。比如:被采集的設(shè)備斷電很久后恢復(fù)使用。因此這條數(shù)據(jù)雖然看似亂序,但實際上和正常數(shù)據(jù)差別不大。
- “1970-01-01 xxxxxxxx” ,這條數(shù)據(jù)在落盤時和該表數(shù)據(jù)塊的時間范圍產(chǎn)生了交集:早在 2.0 當(dāng)中,如果落盤時的數(shù)據(jù)和已有數(shù)據(jù)塊時間戳相交的時候,亂序數(shù)據(jù)會形成一個子塊追加在數(shù)據(jù)文件中,查詢時需要把子塊的數(shù)據(jù)讀到內(nèi)存中再做排序,當(dāng)子塊比較多的時候就會影響查詢性能——經(jīng)過重新設(shè)計后,在 3.0 當(dāng)中亂序數(shù)據(jù)和原有數(shù)據(jù)將會合并重寫為新的數(shù)據(jù)塊,以追加的方式寫入數(shù)據(jù)文件中并且重寫索引,而舊的數(shù)據(jù)塊則被視為碎片文件。這樣一來,處理數(shù)據(jù)的成本就被轉(zhuǎn)嫁給了落盤操作,因此對后續(xù)的查詢基本沒有影響。
綜上,在亂序數(shù)據(jù)寫入硬盤的時候,由于數(shù)據(jù)塊和索引文件均是新生成的,因此它對于后續(xù)的查詢是比較友好的??紤]到亂序數(shù)據(jù)一定是業(yè)務(wù)上的偶發(fā)場景,因此這樣處理基本不會造成性能負(fù)擔(dān)。即便是產(chǎn)生了少部分由于亂序帶來的碎片數(shù)據(jù)、無效數(shù)據(jù)塊也都可以由企業(yè)版功能 compact 清除或者重組。
從很多角度來說,TDengine 3.0 都已經(jīng)達(dá)成了長足的優(yōu)化。因此隨著 2.0 時代逐步進入尾聲,我們也希望大家可以盡早從 2.0 切換到 3.0 之上:《如何把數(shù)據(jù)從 TDengine 2.x 遷移到 3.x ?》。



互聯(lián)網(wǎng).png)



-1.png)







證.png)


伙伴.png)
伙伴.png)
伙伴.png)



