无码人妻精品一区二区三18禁,影音先锋男人AV橹橹色,污污污污污污www网站免费,日韩成人av无码一区二区三区,欧美性受xxxx狂喷水

數據模型和整體架構

數據模型

物聯網典型場景

在典(dian)型(xing)的(de)(de)(de)物聯網、車聯網、運維監測場景中,往(wang)(wang)往(wang)(wang)有(you)(you)多種不(bu)同(tong)類(lei)型(xing)的(de)(de)(de)數據(ju)(ju)采(cai)(cai)(cai)集(ji)設備(bei),采(cai)(cai)(cai)集(ji)一(yi)個(ge)到多個(ge)不(bu)同(tong)的(de)(de)(de)物理量。而同(tong)一(yi)種采(cai)(cai)(cai)集(ji)設備(bei)類(lei)型(xing),往(wang)(wang)往(wang)(wang)又有(you)(you)多個(ge)具體的(de)(de)(de)采(cai)(cai)(cai)集(ji)設備(bei)分(fen)布在不(bu)同(tong)的(de)(de)(de)地點。大數據(ju)(ju)處理系(xi)統(tong)就(jiu)是要(yao)將各種采(cai)(cai)(cai)集(ji)的(de)(de)(de)數據(ju)(ju)匯總,然后(hou)進行計算和分(fen)析。對于同(tong)一(yi)類(lei)設備(bei),其(qi)采(cai)(cai)(cai)集(ji)的(de)(de)(de)數據(ju)(ju)都是很規則的(de)(de)(de)。以智能(neng)電(dian)(dian)表為例,假設每個(ge)智能(neng)電(dian)(dian)表采(cai)(cai)(cai)集(ji)電(dian)(dian)流、電(dian)(dian)壓、相(xiang)位(wei)三個(ge)量,其(qi)采(cai)(cai)(cai)集(ji)的(de)(de)(de)數據(ju)(ju)類(lei)似(si)如下的(de)(de)(de)表格:

設備ID 時間戳 采集量 標簽
Device ID Time Stamp current voltage phase location groupId
d1001 1538548685000 10.3 219 0.31 Beijing.Chaoyang 2
d1002 1538548684000 10.2 220 0.23 Beijing.Chaoyang 3
d1003 1538548686500 11.5 221 0.35 Beijing.Haidian 3
d1004 1538548685500 13.4 223 0.29 Beijing.Haidian 2
d1001 1538548695000 12.6 218 0.33 Beijing.Chaoyang 2
d1004 1538548696600 11.8 221 0.28 Beijing.Haidian 2
d1002 1538548696650 10.3 218 0.25 Beijing.Chaoyang 3
d1001 1538548696800 12.3 221 0.31 Beijing.Chaoyang 2
表 1:智能電表數據示例

每一(yi)條記錄都有設備(bei) ID,時(shi)間戳,采(cai)集的(de)物理量(如(ru)上圖(tu)中的(de)電流、電壓、相位),還有與(yu)每個設備(bei)相關的(de)靜態標簽(如(ru)上述表1中的(de)位置 Location 和分組 groupId)。每個設備(bei)是受外界的(de)觸(chu)發,或按照設定的(de)周期采(cai)集數據(ju)(ju)。采(cai)集的(de)數據(ju)(ju)點是時(shi)序的(de),是一(yi)個數據(ju)(ju)流。

數據特征

除(chu)時序特征外(wai),仔細研究發現,物(wu)聯網(wang)、車聯網(wang)、運維(wei)監測類數據還(huan)具有很多其(qi)他明顯的(de)特征:

  1. 數據高度結構化;
  2. 數據極少有更新或刪除操作;
  3. 無需傳統數據庫的事務處理;
  4. 相對互聯網應用,寫多讀少;
  5. 流量平穩,根據設備數量和采集頻次,可以預測出來;
  6. 用戶關注的是一段時間的趨勢,而不是某一特定時間點的值;
  7. 數據有保留期限;
  8. 數據的查詢分析一定是基于時間段和空間區域;
  9. 除存儲、查詢操作外,還需要各種統計和實時計算操作;
  10. 數據量巨大,一天可能采集的數據就可以超過 100 億條。

充分利用(yong)上述特(te)征,TDengine 采取了(le)經特(te)殊優化的存儲(chu)和計算(suan)設計來處理時序數據,它將系(xi)統處理能(neng)力顯著提高,同時大幅降低了(le)系(xi)統運維的復(fu)雜度。

關系型數據庫模型

因為(wei)采集的數據(ju)(ju)一般(ban)是結構化(hua)數據(ju)(ju),同時為(wei)降低(di)學習(xi)門檻,TDengine 采用傳統的關系型數據(ju)(ju)庫模(mo)型管理數據(ju)(ju)。因此用戶(hu)需要先創(chuang)建庫,然后(hou)創(chuang)建表,之后(hou)才(cai)能插入或查詢數據(ju)(ju)。TDengine 采用的是結構化(hua)存儲,而不是 NoSQL 的 key-value 存儲。

一個數據采集點一張表

為充分利用其數據的時序性和其他數據特點,TDengine 要求對每個數據采集點單獨建表(比如有一(yi)千萬個智能電(dian)表(biao),就需(xu)創建(jian)一(yi)千萬張表(biao),上述表(biao)格中的 d1001, d1002, d1003, d1004 都需(xu)單獨(du)建(jian)表(biao)),用來存(cun)儲這個采集點(dian)所采集的時(shi)序數據。這種設(she)計有幾大優點(dian):

  1. 能保證一個采集點的數據在存儲介質上是以塊為單位連續存儲的。如果讀取一個時間段的數據,它能大幅減少隨機讀取操作,成數量級的提升讀取和查詢速度。
  2. 由于不同采集設備產生數據的過程完全獨立,每個設備的數據源是唯一的,一張表也就只有一個寫入者,這樣就可采用無鎖方式來寫,寫入速度就能大幅提升。
  3. 對于一個數據采集點而言,其產生的數據是時序的,因此寫的操作可用追加的方式實現,進一步大幅提高數據寫入速度。

如果采用傳統的方式,將多個設備的數據寫入一張表,由于網絡延時不可控,不同設備的數據到達服務器的時序是無法保證的,寫入操作是要有鎖保護的,而且一個設備的數據是難以保證連續存儲在一起的。采用一個數據采集點一張表的方式,能最大程度的保證單個數據采集點的插入和查詢的性能是最優的。

TDengine 建議(yi)用數(shu)(shu)據采(cai)集(ji)點的(de)名字(zi)(如(ru)上表(biao)(biao)中(zhong)的(de) D1001)來做(zuo)表(biao)(biao)名。每(mei)個(ge)數(shu)(shu)據采(cai)集(ji)點可能同(tong)時(shi)采(cai)集(ji)多(duo)個(ge)物理量(liang)(liang)(如(ru)上表(biao)(biao)中(zhong)的(de) current, voltage, phase),每(mei)個(ge)物理量(liang)(liang)對(dui)應一(yi)張表(biao)(biao)中(zhong)的(de)一(yi)列(lie),數(shu)(shu)據類型(xing)可以(yi)是整(zheng)型(xing)、浮點型(xing)、字(zi)符(fu)串等(deng)。除此(ci)之(zhi)外,表(biao)(biao)的(de)第一(yi)列(lie)必(bi)須是時(shi)間戳,即數(shu)(shu)據類型(xing)為 timestamp。對(dui)采(cai)集(ji)的(de)數(shu)(shu)據,TDengine 將自(zi)動按照(zhao)時(shi)間戳建立索(suo)引,但對(dui)采(cai)集(ji)的(de)物理量(liang)(liang)不(bu)建任(ren)何(he)索(suo)引。數(shu)(shu)據用列(lie)式存儲方式保(bao)存。

超級表:同一類型數據采集點的集合

由于一個數據采集(ji)點一張(zhang)表,導致表的(de)(de)數量(liang)巨增(zeng),難以管理,而且(qie)應用(yong)經常需(xu)要做采集(ji)點之間(jian)的(de)(de)聚合操(cao)作(zuo),聚合的(de)(de)操(cao)作(zuo)也變得復雜起來。為解決(jue)這個問題,TDengine 引入超級(ji)表(Super Table,簡(jian)稱為 STable)的(de)(de)概念。

超(chao)級表(biao)是(shi)指(zhi)某一(yi)特(te)定(ding)類(lei)(lei)型(xing)的(de)(de)數(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)(ji)點(dian)(dian)的(de)(de)集(ji)(ji)合(he)(he)。同一(yi)類(lei)(lei)型(xing)的(de)(de)數(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)(ji)點(dian)(dian),其表(biao)的(de)(de)結(jie)構是(shi)完全一(yi)樣(yang)的(de)(de),但每個(ge)表(biao)(數(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)(ji)點(dian)(dian))的(de)(de)靜態屬性(標(biao)(biao)簽(qian)(qian))是(shi)不(bu)一(yi)樣(yang)的(de)(de)。描述一(yi)個(ge)超(chao)級表(biao)(某一(yi)特(te)定(ding)類(lei)(lei)型(xing)的(de)(de)數(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)(ji)點(dian)(dian)的(de)(de)集(ji)(ji)合(he)(he)),除需要(yao)定(ding)義采(cai)(cai)(cai)集(ji)(ji)量的(de)(de)表(biao)結(jie)構之(zhi)外,還需要(yao)定(ding)義其標(biao)(biao)簽(qian)(qian)的(de)(de) schema,標(biao)(biao)簽(qian)(qian)的(de)(de)數(shu)(shu)據(ju)類(lei)(lei)型(xing)可以(yi)(yi)是(shi)整數(shu)(shu)、浮(fu)點(dian)(dian)數(shu)(shu)、字符(fu)串,標(biao)(biao)簽(qian)(qian)可以(yi)(yi)有多個(ge),可以(yi)(yi)事后增加(jia)、刪除或修改。如果整個(ge)系統有 N 個(ge)不(bu)同類(lei)(lei)型(xing)的(de)(de)數(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)(ji)點(dian)(dian),就需要(yao)建立(li) N 個(ge)超(chao)級表(biao)。

在 TDengine 的設計里,表用來代表一個具體的數據采集點,超級表用來代表一組相同類型的數據采集點集合。當為某個具體數據采集點創建表時,用戶使用超級表的定義做模板,同時指定該具體采集點(表)的標簽值。與傳統的關系型數據庫相比,表(一個數據采集點)是帶有靜態標簽的,而且這些標簽可以事后增加、刪除、修改。一張超級表包含有多張表,這些表具有相同的時序數據 schema,但帶有不同的標簽值

當對(dui)多個具有相(xiang)同數據(ju)(ju)類型(xing)的(de)數據(ju)(ju)采集(ji)點進(jin)(jin)行(xing)聚(ju)合(he)操作(zuo)時,TDengine 會先把(ba)滿足標(biao)簽過濾條件的(de)表(biao)從超級表(biao)中找(zhao)出來,然后再掃描這些表(biao)的(de)時序(xu)數據(ju)(ju),進(jin)(jin)行(xing)聚(ju)合(he)操作(zuo),這樣需要(yao)掃描的(de)數據(ju)(ju)集(ji)會大幅減少,從而顯著提高聚(ju)合(he)計算的(de)性能。

集群與基本邏輯單元

TDengine 的(de)設計是基于(yu)單(dan)個硬件(jian)(jian)、軟件(jian)(jian)系(xi)統不(bu)可靠,基于(yu)任(ren)何單(dan)臺(tai)計算(suan)機都無法提供足夠計算(suan)能力和(he)存儲(chu)能力處理海(hai)量數據的(de)假設進(jin)行(xing)設計的(de)。因此 TDengine 從研發(fa)的(de)第(di)一(yi)天起,就按(an)照分布式高可靠架構進(jin)行(xing)設計,是支(zhi)持水平擴展的(de),這樣任(ren)何單(dan)臺(tai)或(huo)多臺(tai)服務器發(fa)生硬件(jian)(jian)故障或(huo)軟件(jian)(jian)錯誤都不(bu)影響系(xi)統的(de)可用(yong)性和(he)可靠性。同時(shi),通過節點虛擬化(hua)并輔(fu)以自動化(hua)負載均衡技術,TDengine 能最高效率地利用(yong)異構集群中的(de)計算(suan)和(he)存儲(chu)資源降低硬件(jian)(jian)投資。

主要邏輯單元

TDengine 分布式架構的邏輯結構圖(tu)如下(xia):

TDengine架構示意圖

圖 1 TDengine架構示意圖

一(yi)個(ge)(ge)完整的 TDengine 系(xi)統(tong)是運行(xing)在一(yi)到多(duo)個(ge)(ge)物理節點(dian)上(shang)的,邏輯上(shang),它包含數(shu)據(ju)節點(dian)(dnode)、TDengine 應用驅動(dong)(taosc)以(yi)及應用(app)。系(xi)統(tong)中存在一(yi)到多(duo)個(ge)(ge)數(shu)據(ju)節點(dian),這些數(shu)據(ju)節點(dian)組成一(yi)個(ge)(ge)集(ji)群(cluster)。應用通過 taosc 的 API 與 TDengine 集(ji)群進(jin)行(xing)互動(dong)。下面對每個(ge)(ge)邏輯單元進(jin)行(xing)簡要介紹。

物理節點(pnode): pnode 是一獨立運行、擁有自己的計算、存儲和網絡能力的計算機,可以是安裝有OS的物理機、虛擬機或 Docker 容器。物理節點由其配置的 FQDN (Fully Qualified Domain Name)來標識。TDengine 完全依賴 FQDN 來進行網絡通訊,如果不了解 FQDN,請看博文《一篇文章說清楚 TDengine 的 FQDN》

數據節點(dnode): dnode 是(shi) TDengine 服務器(qi)側執行(xing)代碼(ma) taosd 在物理(li)節點(dian)(dian)(dian)(dian)上的(de)(de)一(yi)(yi)個(ge)運(yun)行(xing)實(shi)例,一(yi)(yi)個(ge)工(gong)作的(de)(de)系統(tong)(tong)必須有至少一(yi)(yi)個(ge)數據節點(dian)(dian)(dian)(dian)。dnode 包含零(ling)到多個(ge)邏(luo)輯的(de)(de)虛擬節點(dian)(dian)(dian)(dian)(vnode),零(ling)或者(zhe)至多一(yi)(yi)個(ge)邏(luo)輯的(de)(de)管(guan)理(li)節點(dian)(dian)(dian)(dian)(mnode)。dnode 在系統(tong)(tong)中的(de)(de)唯一(yi)(yi)標識由實(shi)例的(de)(de) End Point (EP)決定。EP 是(shi) dnode 所在物理(li)節點(dian)(dian)(dian)(dian)的(de)(de) FQDN (Fully Qualified Domain Name)和(he)系統(tong)(tong)所配置的(de)(de)網絡端口號(Port)的(de)(de)組合。通過配置不同的(de)(de)端口,一(yi)(yi)個(ge)物理(li)節點(dian)(dian)(dian)(dian)(一(yi)(yi)臺物理(li)機、虛擬機或容器(qi))可以(yi)運(yun)行(xing)多個(ge)實(shi)例,或有多個(ge)數據節點(dian)(dian)(dian)(dian)。

虛擬節點(vnode): 為更好的(de)(de)(de)(de)支持數(shu)據(ju)分片、負載均(jun)衡,防止(zhi)數(shu)據(ju)過熱(re)或傾斜(xie),數(shu)據(ju)節(jie)點被虛擬化成多個(ge)虛擬節(jie)點(vnode,圖中 V2, V3, V4等)。每個(ge) vnode 都是一(yi)(yi)(yi)(yi)(yi)個(ge)相對(dui)獨(du)立的(de)(de)(de)(de)工作(zuo)單元,是時序數(shu)據(ju)存(cun)儲的(de)(de)(de)(de)基本單元,具有獨(du)立的(de)(de)(de)(de)運行線程、內存(cun)空間與持久化存(cun)儲的(de)(de)(de)(de)路徑。一(yi)(yi)(yi)(yi)(yi)個(ge) vnode 包(bao)含一(yi)(yi)(yi)(yi)(yi)定數(shu)量的(de)(de)(de)(de)表(數(shu)據(ju)采(cai)集點)。當創(chuang)建一(yi)(yi)(yi)(yi)(yi)張新表時,系統(tong)會檢查是否需要創(chuang)建新的(de)(de)(de)(de) vnode。一(yi)(yi)(yi)(yi)(yi)個(ge)數(shu)據(ju)節(jie)點上能創(chuang)建的(de)(de)(de)(de) vnode 的(de)(de)(de)(de)數(shu)量取決(jue)于(yu)該數(shu)據(ju)節(jie)點所(suo)在物理(li)節(jie)點的(de)(de)(de)(de)硬件資源。一(yi)(yi)(yi)(yi)(yi)個(ge) vnode 只(zhi)屬于(yu)一(yi)(yi)(yi)(yi)(yi)個(ge) DB,但一(yi)(yi)(yi)(yi)(yi)個(ge) DB 可以有多個(ge) vnode。一(yi)(yi)(yi)(yi)(yi)個(ge) vnode 除存(cun)儲的(de)(de)(de)(de)時序數(shu)據(ju)外,也(ye)保(bao)存(cun)有所(suo)包(bao)含的(de)(de)(de)(de)表的(de)(de)(de)(de) schema、標簽值(zhi)等。一(yi)(yi)(yi)(yi)(yi)個(ge)虛擬節(jie)點由所(suo)屬的(de)(de)(de)(de)數(shu)據(ju)節(jie)點的(de)(de)(de)(de)EP,以及所(suo)屬的(de)(de)(de)(de) VGroup ID 在系統(tong)內唯一(yi)(yi)(yi)(yi)(yi)標識(shi),由管理(li)節(jie)點創(chuang)建并管理(li)。

管理節點(mnode): 一(yi)個虛(xu)擬的(de)(de)邏輯單元,負責所(suo)有數(shu)(shu)據節(jie)點運行(xing)(xing)狀態的(de)(de)監控和維護(hu),以及節(jie)點之間(jian)的(de)(de)負載(zai)均衡(圖(tu)中 M)。同時,管理節(jie)點也負責元數(shu)(shu)據(包括用(yong)(yong)戶、數(shu)(shu)據庫、表、靜態標簽等(deng))的(de)(de)存儲和管理,因此也稱為 Meta Node。TDengine 集(ji)(ji)群中可配(pei)置多(duo)(duo)個(最多(duo)(duo)不超過 3 個) mnode,它們自(zi)動構(gou)建(jian)成為一(yi)個虛(xu)擬管理節(jie)點組(圖(tu)中 M0, M1, M2)。mnode 間(jian)采(cai)用(yong)(yong) master/slave 的(de)(de)機制(zhi)進(jin)行(xing)(xing)管理,而且(qie)采(cai)取(qu)強一(yi)致方式進(jin)行(xing)(xing)數(shu)(shu)據同步, 任何數(shu)(shu)據更新(xin)操作只能在 Master 上(shang)進(jin)行(xing)(xing)。mnode 集(ji)(ji)群的(de)(de)創建(jian)由(you)系統(tong)自(zi)動完成,無需(xu)人工干預。每個 dnode 上(shang)至(zhi)多(duo)(duo)有一(yi)個 mnode,由(you)所(suo)屬的(de)(de)數(shu)(shu)據節(jie)點的(de)(de)EP來唯一(yi)標識。每個 dnode 通過內部消息交互(hu)自(zi)動獲(huo)取(qu)整(zheng)個集(ji)(ji)群中所(suo)有 mnode 所(suo)在的(de)(de) dnode 的(de)(de)EP。

虛擬節點組(VGroup): 不同(tong)數(shu)據(ju)節(jie)點上的(de)(de)(de) vnode 可(ke)以組(zu)成一個(ge)(ge)(ge)(ge)虛(xu)(xu)擬節(jie)點組(zu)(vnode group)來(lai)保證系(xi)(xi)統(tong)的(de)(de)(de)高可(ke)靠。虛(xu)(xu)擬節(jie)點組(zu)內采取 master/slave 的(de)(de)(de)方式進(jin)行管(guan)理(li)(li)。寫操作只(zhi)能在(zai) master vnode 上進(jin)行,系(xi)(xi)統(tong)采用異(yi)步復制(zhi)的(de)(de)(de)方式將數(shu)據(ju)同(tong)步到 slave vnode,這樣確保了一份(fen)數(shu)據(ju)在(zai)多個(ge)(ge)(ge)(ge)物理(li)(li)節(jie)點上有拷貝。一個(ge)(ge)(ge)(ge) vgroup 里(li)虛(xu)(xu)擬節(jie)點個(ge)(ge)(ge)(ge)數(shu)就(jiu)(jiu)是數(shu)據(ju)的(de)(de)(de)副(fu)本(ben)數(shu)。如(ru)果一個(ge)(ge)(ge)(ge) DB 的(de)(de)(de)副(fu)本(ben)數(shu)為 N,系(xi)(xi)統(tong)必須有至少 N 數(shu)據(ju)節(jie)點。副(fu)本(ben)數(shu)在(zai)創建DB時(shi)通過參數(shu) replica 可(ke)以指定,缺(que)省為 1。使用 TDengine 的(de)(de)(de)多副(fu)本(ben)特性,可(ke)以不再需要(yao)昂貴的(de)(de)(de)磁(ci)盤陣(zhen)列等存儲(chu)設備,就(jiu)(jiu)可(ke)以獲得同(tong)樣的(de)(de)(de)數(shu)據(ju)高可(ke)靠性。虛(xu)(xu)擬節(jie)點組(zu)由(you)管(guan)理(li)(li)節(jie)點創建、管(guan)理(li)(li),并且由(you)管(guan)理(li)(li)節(jie)點分配一個(ge)(ge)(ge)(ge)系(xi)(xi)統(tong)唯(wei)一的(de)(de)(de) ID,VGroup ID。如(ru)果兩個(ge)(ge)(ge)(ge)虛(xu)(xu)擬節(jie)點的(de)(de)(de) vnode group ID 相同(tong),說明他們(men)屬于同(tong)一個(ge)(ge)(ge)(ge)組(zu),數(shu)據(ju)互為備份(fen)。虛(xu)(xu)擬節(jie)點組(zu)里(li)虛(xu)(xu)擬節(jie)點的(de)(de)(de)個(ge)(ge)(ge)(ge)數(shu)是可(ke)以動態改變的(de)(de)(de),容許只(zhi)有一個(ge)(ge)(ge)(ge),也就(jiu)(jiu)是沒(mei)有數(shu)據(ju)復制(zhi)。VGroup ID 是永遠不變的(de)(de)(de),即(ji)使一個(ge)(ge)(ge)(ge)虛(xu)(xu)擬節(jie)點組(zu)被刪除,它的(de)(de)(de)ID也不會被收回重復利(li)用。

TAOSC: taosc 是 TDengine 給應(ying)(ying)用(yong)(yong)(yong)提(ti)供的(de)驅動程序(driver),負(fu)責處理應(ying)(ying)用(yong)(yong)(yong)與(yu)集群的(de)接(jie)(jie)口交互(hu),提(ti)供 C/C++ 語言原生接(jie)(jie)口,內嵌于(yu) JDBC、C#、Python、Go、Node.js 語言連接(jie)(jie)庫(ku)里。應(ying)(ying)用(yong)(yong)(yong)都(dou)是通過 taosc 而不是直接(jie)(jie)連接(jie)(jie)集群中(zhong)的(de)數(shu)據節點(dian)與(yu)整個(ge)集群進(jin)行(xing)(xing)交互(hu)的(de)。這個(ge)模塊負(fu)責獲(huo)取并緩存(cun)元(yuan)數(shu)據;將(jiang)插入、查詢(xun)等(deng)請(qing)求轉發到正確的(de)數(shu)據節點(dian);在(zai)把(ba)結果返(fan)回(hui)給應(ying)(ying)用(yong)(yong)(yong)時,還需要負(fu)責最后一級的(de)聚合、排序、過濾等(deng)操作。對于(yu) JDBC、C/C++、C#、Python、Go、Node.js 接(jie)(jie)口而言,這個(ge)模塊是在(zai)應(ying)(ying)用(yong)(yong)(yong)所處的(de)物理節點(dian)上運行(xing)(xing)。同時,為支持全分布式的(de) RESTful 接(jie)(jie)口,taosc 在(zai) TDengine 集群的(de)每(mei)個(ge) dnode 上都(dou)有一運行(xing)(xing)實例。

節點之間的通訊

通訊方式:TDengine 系統的(de)(de)各個數(shu)(shu)據(ju)節點(dian)之(zhi)(zhi)間,以及(ji)應(ying)用(yong)驅動與各數(shu)(shu)據(ju)節點(dian)之(zhi)(zhi)間的(de)(de)通訊是通過 TCP/UDP 進行(xing)的(de)(de)。因(yin)(yin)為考慮到物聯網場景,數(shu)(shu)據(ju)寫入(ru)的(de)(de)包一般不大,因(yin)(yin)此 TDengine 除(chu)采(cai)用(yong) TCP 做傳輸(shu)(shu)之(zhi)(zhi)外,還采(cai)用(yong) UDP 方(fang)式(shi),因(yin)(yin)為 UDP 更加高(gao)效,而且不受連接數(shu)(shu)的(de)(de)限(xian)制(zhi)。TDengine 實現了自己的(de)(de)超(chao)時、重傳、確(que)認等機制(zhi),以確(que)保 UDP 的(de)(de)可靠傳輸(shu)(shu)。對于(yu)數(shu)(shu)據(ju)量不到15K的(de)(de)數(shu)(shu)據(ju)包,采(cai)取(qu) UDP 的(de)(de)方(fang)式(shi)進行(xing)傳輸(shu)(shu),超(chao)過 15K 的(de)(de),或者是查詢類的(de)(de)操作,自動采(cai)取(qu) TCP 的(de)(de)方(fang)式(shi)進行(xing)傳輸(shu)(shu)。同時,TDengine 根據(ju)配置和數(shu)(shu)據(ju)包,會自動對數(shu)(shu)據(ju)進行(xing)壓縮/解壓縮,數(shu)(shu)字簽名/認證等處理。對于(yu)數(shu)(shu)據(ju)節點(dian)之(zhi)(zhi)間的(de)(de)數(shu)(shu)據(ju)復制(zhi),只采(cai)用(yong) TCP 方(fang)式(shi)進行(xing)數(shu)(shu)據(ju)傳輸(shu)(shu)。

FQDN配置:一個數(shu)(shu)(shu)據(ju)節(jie)(jie)點(dian)有(you)一個或(huo)多個 FQDN,可(ke)以在系統配(pei)置文(wen)件 taos.cfg 通(tong)過(guo)參數(shu)(shu)(shu)"fqdn"進(jin)行(xing)指定(ding),如(ru)果沒(mei)有(you)指定(ding),系統將(jiang)自(zi)動獲(huo)取計算機的(de) hostname 作(zuo)為(wei)其 FQDN。如(ru)果節(jie)(jie)點(dian)沒(mei)有(you)配(pei)置 FQDN,可(ke)以直(zhi)接(jie)將(jiang)該節(jie)(jie)點(dian)的(de)配(pei)置參數(shu)(shu)(shu) fqdn 設(she)置為(wei)它的(de)IP地(di)址。但不建議使用 IP,因為(wei) IP 地(di)址可(ke)變,一旦變化,將(jiang)讓(rang)集群(qun)無法正常(chang)(chang)工(gong)作(zuo)。一個數(shu)(shu)(shu)據(ju)節(jie)(jie)點(dian)的(de) EP(End Point) 由 FQDN + Port 組成(cheng)。采用 FQDN,需要(yao)保證 DNS 服(fu)務正常(chang)(chang)工(gong)作(zuo),或(huo)者在節(jie)(jie)點(dian)以及應用所在的(de)節(jie)(jie)點(dian)配(pei)置好 hosts 文(wen)件。另外(wai),這(zhe)個參數(shu)(shu)(shu)值的(de)長(chang)度需要(yao)控(kong)制在 96 個字符以內。

端口配置:一(yi)個(ge)(ge)數據節(jie)點對(dui)外的(de)(de)端口由 TDengine 的(de)(de)系統(tong)配置(zhi)參數 serverPort 決定,對(dui)集群內部通訊的(de)(de)端口是 serverPort+5。為支持多線(xian)程高效的(de)(de)處理 UDP 數據,每個(ge)(ge)對(dui)內和(he)對(dui)外的(de)(de) UDP 連接(jie),都需要占用5個(ge)(ge)連續的(de)(de)端口。

  • 集群內數據節點之間的數據復制操作占用一個 TCP 端口,是 serverPort+10。
  • 集群數據節點對外提供 RESTful 服務占用一個 TCP 端口,是 serverPort+11。
  • 集群內數據節點與 Arbitrator 節點之間通訊占用一個 TCP 端口,是 serverPort+12。

因此一個數據節點總的端口范圍為 serverPort 到 serverPort+12,總共 13 個 TCP/UDP 端口。使用時,需要確保防火墻將這些端口打開。每個數據節點可以配置不同的 serverPort。(詳細的端口情況請參見 TDengine 2.0 端口說明

集群對外連接:TDengine 集(ji)群可(ke)以容納單個、多(duo)個甚至幾千個數(shu)(shu)(shu)據節點(dian)。應用只需(xu)要向集(ji)群中任何一(yi)個數(shu)(shu)(shu)據節點(dian)發起連接即可(ke),連接需(xu)要提(ti)供的(de)網(wang)絡(luo)參數(shu)(shu)(shu)是一(yi)數(shu)(shu)(shu)據節點(dian)的(de) End Point(FQDN加配(pei)置(zhi)的(de)端(duan)口號(hao))。通過命令行(xing)CLI啟動應用 taos 時,可(ke)以通過選項-h來指定數(shu)(shu)(shu)據節點(dian)的(de) FQDN, -P 來指定其配(pei)置(zhi)的(de)端(duan)口號(hao),如果端(duan)口不(bu)配(pei)置(zhi),將采用 TDengine 的(de)系統配(pei)置(zhi)參數(shu)(shu)(shu) serverPort。

集群內部通訊:各個(ge)數據節點之(zhi)間通過 TCP/UDP 進(jin)行連接(jie)。一個(ge)數據節點啟動時,將獲(huo)取 mnode 所在的 dnode 的 EP 信息,然后與(yu)系統中的 mnode 建立起連接(jie),交換信息。獲(huo)取 mnode 的 EP 信息有(you)三步:

  1. 檢查 mnodeEpSet.json 文件是否存在,如果不存在或不能正常打開獲得 mnode EP 信息,進入第二步;
  2. 檢查系統配置文件 taos.cfg,獲取節點配置參數 firstEp、secondEp(這兩個參數指定的節點可以是不帶 mnode 的普通節點,這樣的話,節點被連接時會嘗試重定向到 mnode 節點),如果不存在或者 taos.cfg 里沒有這兩個配置參數,或無效,進入第三步;
  3. 將自己的EP設為 mnode EP,并獨立運行起來。

獲取 mnode EP 列表后,數(shu)據(ju)節點發(fa)起連(lian)(lian)接(jie),如果(guo)連(lian)(lian)接(jie)成(cheng)功,則(ze)成(cheng)功加入進工(gong)作(zuo)的(de)集群(qun),如果(guo)不(bu)成(cheng)功,則(ze)嘗(chang)(chang)試(shi)(shi) mnode EP 列表中的(de)下一個(ge)。如果(guo)都嘗(chang)(chang)試(shi)(shi)了,但連(lian)(lian)接(jie)都仍然失敗,則(ze)休(xiu)眠幾(ji)秒后,再(zai)進行嘗(chang)(chang)試(shi)(shi)。

MNODE的選擇:TDengine 邏輯上(shang)有(you)管(guan)理節(jie)(jie)點(dian)(dian),但沒有(you)單獨的(de)(de)(de)(de)執(zhi)行(xing)(xing)代碼,服務器側(ce)只(zhi)有(you)一套(tao)執(zhi)行(xing)(xing)代碼 taosd。那么哪(na)個(ge)(ge)數(shu)(shu)據(ju)(ju)節(jie)(jie)點(dian)(dian)會是(shi)管(guan)理節(jie)(jie)點(dian)(dian)呢?這是(shi)系統自(zi)(zi)(zi)(zi)動決(jue)定的(de)(de)(de)(de),無需任(ren)何人工(gong)干預。原則如(ru)下(xia):一個(ge)(ge)數(shu)(shu)據(ju)(ju)節(jie)(jie)點(dian)(dian)啟(qi)(qi)動時,會檢查自(zi)(zi)(zi)(zi)己的(de)(de)(de)(de) End Point, 并與獲(huo)取的(de)(de)(de)(de) mnode EP List 進行(xing)(xing)比(bi)對,如(ru)果在其中,該數(shu)(shu)據(ju)(ju)節(jie)(jie)點(dian)(dian)認為(wei)自(zi)(zi)(zi)(zi)己應該啟(qi)(qi)動 mnode 模塊(kuai),成為(wei) mnode。如(ru)果自(zi)(zi)(zi)(zi)己的(de)(de)(de)(de) EP 不在 mnode EP List 里,則不啟(qi)(qi)動 mnode 模塊(kuai)。在系統的(de)(de)(de)(de)運行(xing)(xing)過程中,由于負載均(jun)衡、宕機等原因,mnode 有(you)可能遷移(yi)至新的(de)(de)(de)(de) dnode,但一切都是(shi)透(tou)明的(de)(de)(de)(de),無需人工(gong)干預,配置(zhi)參(can)數(shu)(shu)的(de)(de)(de)(de)修改,是(shi) mnode 自(zi)(zi)(zi)(zi)己根據(ju)(ju)資源做(zuo)出的(de)(de)(de)(de)決(jue)定。

新數據節點的加入:系統(tong)有(you)了一(yi)(yi)個(ge)數(shu)(shu)(shu)據節點后,就(jiu)已經成為一(yi)(yi)個(ge)工(gong)作(zuo)的(de)系統(tong)。添加新的(de)節點進集群(qun)時(shi),有(you)兩個(ge)步(bu)驟,第一(yi)(yi)步(bu):使用(yong) TDengine CLI 連接到(dao)現有(you)工(gong)作(zuo)的(de)數(shu)(shu)(shu)據節點,然后用(yong)命(ming)令"create dnode"將新的(de)數(shu)(shu)(shu)據節點的(de) End Point 添加進去; 第二步(bu):在新的(de)數(shu)(shu)(shu)據節點的(de)系統(tong)配置(zhi)(zhi)參數(shu)(shu)(shu)文件 taos.cfg 里,將 firstEp, secondEp 參數(shu)(shu)(shu)設置(zhi)(zhi)為現有(you)集群(qun)中(zhong)任意兩個(ge)數(shu)(shu)(shu)據節點的(de) EP 即(ji)可。具體添加的(de)詳細步(bu)驟請見詳細的(de)用(yong)戶手冊。這(zhe)樣就(jiu)把集群(qun)一(yi)(yi)步(bu)一(yi)(yi)步(bu)的(de)建立起(qi)來。

重定向:無論是(shi)(shi) dnode 還是(shi)(shi) taosc,最先都是(shi)(shi)要發起與 mnode 的(de)連(lian)接,但 mnode 是(shi)(shi)系統自動創建并(bing)(bing)維護(hu)的(de),因此對于用(yong)戶來(lai)(lai)說,并(bing)(bing)不知道哪個(ge) dnode 在運(yun)行 mnode。TDengine 只要求向(xiang)系統中任(ren)何一(yi)個(ge)工作的(de) dnode 發起連(lian)接即可。因為(wei)任(ren)何一(yi)個(ge)正在運(yun)行的(de) dnode,都維護(hu)有(you)目(mu)前運(yun)行的(de) mnode EP List。當收到(dao)一(yi)個(ge)來(lai)(lai)自新啟動的(de) dnode 或(huo) taosc 的(de)連(lian)接請求,如果自己不是(shi)(shi) mnode,則將 mnode EP List 回復給對方,taosc 或(huo)新啟動的(de) dnode 收到(dao)這個(ge) list, 就(jiu)重新嘗(chang)試建立連(lian)接。當 mnode EP List 發生改變,通(tong)過節(jie)點(dian)之間的(de)消息交互,各個(ge)數據節(jie)點(dian)就(jiu)很快獲取最新列表,并(bing)(bing)通(tong)知 taosc。

一個典型的消息流程

為解釋 vnode、mnode、taosc 和應用之間的關系以及各(ge)自扮演(yan)的角色,下面對寫入數據(ju)這個典型(xing)操作的流程(cheng)進(jin)行(xing)剖(pou)析。

TDengine典型的操作流程

圖 2 TDengine 典型的操作流程
  1. 應用通過 JDBC 或其他API接口發起插入數據的請求。
  2. taosc 會檢查緩存,看是否保存有該表的 meta data。如果有,直接到第 4 步。如果沒有,taosc 將向 mnode 發出 get meta-data 請求。
  3. mnode 將該表的 meta-data 返回給 taosc。Meta-data 包含有該表的 schema, 而且還有該表所屬的 vgroup信息(vnode ID 以及所在的 dnode 的 End Point,如果副本數為 N,就有 N 組 End Point)。如果 taosc 遲遲得不到 mnode 回應,而且存在多個 mnode, taosc 將向下一個 mnode 發出請求。
  4. taosc 向 master vnode 發起插入請求。
  5. vnode 插入數據后,給 taosc 一個應答,表示插入成功。如果 taosc 遲遲得不到 vnode 的回應,taosc 會認為該節點已經離線。這種情況下,如果被插入的數據庫有多個副本,taosc 將向 vgroup 里下一個 vnode 發出插入請求。
  6. taosc 通知 APP,寫入成功。

對于第二和第三步,taosc 啟動(dong)時,并不(bu)知(zhi)道 mnode 的(de)(de) End Point,因(yin)此會(hui)(hui)直接(jie)(jie)向(xiang)配置的(de)(de)集群對外(wai)服務的(de)(de) End Point 發(fa)起請(qing)求(qiu)。如果(guo)接(jie)(jie)收到該(gai)請(qing)求(qiu)的(de)(de) dnode 并沒有配置 mnode,該(gai) dnode 會(hui)(hui)在回復的(de)(de)消息中告知(zhi)mnode EP 列表,這樣 taosc 會(hui)(hui)重新(xin)向(xiang)新(xin)的(de)(de) mnode 的(de)(de) EP 發(fa)出獲取 meta-data 的(de)(de)請(qing)求(qiu)。

對(dui)于第四和第五步,沒有(you)緩(huan)(huan)存(cun)的(de)(de)情況下,taosc 無(wu)法(fa)知道虛擬節(jie)點組里誰是(shi)(shi)(shi) master,就假(jia)設第一個 vnodeID 就是(shi)(shi)(shi) master,向它(ta)發(fa)出請(qing)求。如果接收(shou)到請(qing)求的(de)(de) vnode 并不是(shi)(shi)(shi) master,它(ta)會(hui)在回復(fu)中(zhong)告知誰是(shi)(shi)(shi) master,這(zhe)樣 taosc 就向建(jian)議(yi)的(de)(de) master vnode 發(fa)出請(qing)求。一旦得到插入成功(gong)的(de)(de)回復(fu),taosc 會(hui)緩(huan)(huan)存(cun) master 節(jie)點的(de)(de)信息。

上述(shu)是插入數(shu)據的(de)流(liu)程,查詢、計算的(de)流(liu)程也完全(quan)一(yi)致。taosc 把這些復雜的(de)流(liu)程全(quan)部封裝屏蔽了,對(dui)于應用(yong)來(lai)說無(wu)感知也無(wu)需任(ren)何(he)特別處(chu)理。

通過 taosc 緩存機制,只有(you)在第一次對一張表操作時(shi),才需要訪問(wen) mnode,因此 mnode 不會(hui)成(cheng)為系統瓶頸。但因為 schema 有(you)可(ke)能變(bian)化,而且 vgroup 有(you)可(ke)能發(fa)生改變(bian)(比如負載(zai)均衡(heng)發(fa)生),因此 taosc 會(hui)定時(shi)和mnode 交互(hu),自動更新緩存。

存儲模型與數據分區、分片

存儲模型

TDengine 存儲的(de)數據(ju)(ju)包括(kuo)采集(ji)的(de)時序數據(ju)(ju)以及(ji)庫(ku)、表相(xiang)關的(de)元數據(ju)(ju)、標簽數據(ju)(ju)等(deng),這些數據(ju)(ju)具體分(fen)(fen)為三部分(fen)(fen):

  • 時序數據:存放于 vnode 里,由 data、head 和 last 三個文件組成,數據量大,查詢量取決于應用場景。容許亂序寫入,但暫時不支持刪除操作,并且僅在 update 參數設置為 1 時允許更新操作。通過采用一個采集點一張表的模型,一個時間段的數據是連續存儲,對單張表的寫入是簡單的追加操作,一次讀,可以讀到多條記錄,這樣保證對單個采集點的插入和查詢操作,性能達到最優。
  • 標簽數據:存放于 vnode 里的 meta 文件,支持增刪改查四個標準操作。數據量不大,有 N 張表,就有 N 條記錄,因此可以全內存存儲。如果標簽過濾操作很多,查詢將十分頻繁,因此 TDengine 支持多核多線程并發查詢。只要計算資源足夠,即使有數千萬張表,過濾結果能毫秒級返回。
  • 元數據:存放于 mnode 里,包含系統節點、用戶、DB、Table Schema 等信息,支持增刪改查四個標準操作。這部分數據的量不大,可以全內存保存,而且由于客戶端有緩存,查詢量也不大。因此目前的設計雖是集中式存儲管理,但不會構成性能瓶頸。

與典型的(de) NoSQL 存儲模型相(xiang)比,TDengine 將(jiang)標簽數(shu)據(ju)與時序(xu)數(shu)據(ju)完(wan)全分離存儲,它(ta)具有(you)兩(liang)大優勢(shi):

  • 能夠極大地降低標簽數據存儲的冗余度:一般的 NoSQL 數據庫或時序數據庫,采用的 K-V 存儲,其中的 Key 包含時間戳、設備 ID、各種標簽。每條記錄都帶有這些重復的內容,浪費存儲空間。而且如果應用要在歷史數據上增加、修改或刪除標簽,需要遍歷數據,重寫一遍,操作成本極其昂貴。
  • 能夠實現極為高效的多表之間的聚合查詢:做多表之間聚合查詢時,先把符合標簽過濾條件的表查找出來,然后再查找這些表相應的數據塊,這樣大幅減少要掃描的數據集,從而大幅提高查詢效率。而且標簽數據采用全內存的結構進行管理和維護,千萬級別規模的標簽數據查詢可以在毫秒級別返回。

數據分片

對于海量的(de)數(shu)(shu)據(ju)管(guan)理,為實(shi)現(xian)水平(ping)擴展,一般(ban)都需要采(cai)取分(fen)片(Sharding)分(fen)區(Partitioning)策略。TDengine 是通(tong)過(guo) vnode 來(lai)實(shi)現(xian)數(shu)(shu)據(ju)分(fen)片的(de),通(tong)過(guo)一個時間段一個數(shu)(shu)據(ju)文件來(lai)實(shi)現(xian)時序數(shu)(shu)據(ju)分(fen)區的(de)。

vnode(虛擬數(shu)(shu)據(ju)節點(dian)(dian))負責(ze)為采集的(de)時序數(shu)(shu)據(ju)提供寫(xie)入(ru)、查(cha)詢和(he)(he)計算(suan)功(gong)能。為便于(yu)負載均衡、數(shu)(shu)據(ju)恢復(fu)、支持(chi)異(yi)構(gou)環(huan)境,TDengine 將一個數(shu)(shu)據(ju)節點(dian)(dian)根據(ju)其計算(suan)和(he)(he)存儲資源(yuan)切(qie)分為多個 vnode。這些 vnode 的(de)管理是TDengine 自動完成的(de),對應用完全透(tou)明(ming)。

對于(yu)單獨一(yi)(yi)(yi)(yi)個(ge)數(shu)(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)點(dian),無論其(qi)數(shu)(shu)(shu)據(ju)量多(duo)大,一(yi)(yi)(yi)(yi)個(ge) vnode(或(huo) vnode group, 如果副本數(shu)(shu)(shu)大于(yu) 1)有足夠的(de)(de)計算資(zi)源和存儲資(zi)源來處理(如果每秒(miao)生(sheng)(sheng)成一(yi)(yi)(yi)(yi)條(tiao) 16 字節的(de)(de)記錄,一(yi)(yi)(yi)(yi)年產生(sheng)(sheng)的(de)(de)原始數(shu)(shu)(shu)據(ju)不(bu)(bu)到(dao) 0.5G),因此 TDengine 將一(yi)(yi)(yi)(yi)張表(biao)(一(yi)(yi)(yi)(yi)個(ge)數(shu)(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)點(dian))的(de)(de)所有數(shu)(shu)(shu)據(ju)都(dou)存放在一(yi)(yi)(yi)(yi)個(ge) vnode 里(li),而不(bu)(bu)會讓同一(yi)(yi)(yi)(yi)個(ge)采(cai)(cai)(cai)集(ji)點(dian)的(de)(de)數(shu)(shu)(shu)據(ju)分布到(dao)兩(liang)個(ge)或(huo)多(duo)個(ge) dnode 上(shang)。而且一(yi)(yi)(yi)(yi)個(ge) vnode 可存儲多(duo)個(ge)數(shu)(shu)(shu)據(ju)采(cai)(cai)(cai)集(ji)點(dian)(表(biao))的(de)(de)數(shu)(shu)(shu)據(ju),一(yi)(yi)(yi)(yi)個(ge) vnode 可容納的(de)(de)表(biao)的(de)(de)數(shu)(shu)(shu)目的(de)(de)上(shang)限為(wei)一(yi)(yi)(yi)(yi)百萬。設計上(shang),一(yi)(yi)(yi)(yi)個(ge) vnode 里(li)所有的(de)(de)表(biao)都(dou)屬于(yu)同一(yi)(yi)(yi)(yi)個(ge) DB。一(yi)(yi)(yi)(yi)個(ge)數(shu)(shu)(shu)據(ju)節點(dian)上(shang),除非特殊配置,一(yi)(yi)(yi)(yi)個(ge) DB 擁有的(de)(de) vnode 數(shu)(shu)(shu)目不(bu)(bu)會超過系統(tong)核的(de)(de)數(shu)(shu)(shu)目。

創(chuang)建(jian) DB 時(shi),系(xi)(xi)(xi)(xi)統并不會(hui)馬上分(fen)配資源。但當(dang)(dang)創(chuang)建(jian)一(yi)張(zhang)表時(shi),系(xi)(xi)(xi)(xi)統將看是(shi)否(fou)有(you)已經分(fen)配的 vnode, 且該 vnode 是(shi)否(fou)有(you)空余的表空間,如果(guo)有(you),立即在該有(you)空位的 vnode 創(chuang)建(jian)表。如果(guo)沒有(you),系(xi)(xi)(xi)(xi)統將從集群(qun)中,根據當(dang)(dang)前的負載情況,在一(yi)個(ge) dnode 上創(chuang)建(jian)一(yi)新的 vnode, 然后創(chuang)建(jian)表。如果(guo)DB有(you)多個(ge)副本(ben),系(xi)(xi)(xi)(xi)統不是(shi)只創(chuang)建(jian)一(yi)個(ge) vnode,而是(shi)一(yi)個(ge) vgroup (虛擬數(shu)據節(jie)點組)。系(xi)(xi)(xi)(xi)統對(dui) vnode 的數(shu)目沒有(you)任何限(xian)制,僅僅受限(xian)于物(wu)理節(jie)點本(ben)身的計算和存儲資源。

每張表的(de) meta data(包含(han) schema, 標(biao)簽等)也存(cun)放于(yu)(yu) vnode 里,而不是集中存(cun)放于(yu)(yu) mnode,實際上這是對(dui) Meta 數據的(de)分片,這樣便于(yu)(yu)高(gao)效并行的(de)進行標(biao)簽過濾操作。

數據分區

TDengine 除(chu) vnode 分片(pian)之外,還對時(shi)(shi)序數(shu)(shu)據(ju)(ju)按照(zhao)時(shi)(shi)間段(duan)(duan)進行分區。每個數(shu)(shu)據(ju)(ju)文件只(zhi)包(bao)含(han)一個時(shi)(shi)間段(duan)(duan)的(de)(de)(de)時(shi)(shi)序數(shu)(shu)據(ju)(ju),時(shi)(shi)間段(duan)(duan)的(de)(de)(de)長度由 DB 的(de)(de)(de)配置參數(shu)(shu) days 決定。這種按時(shi)(shi)間段(duan)(duan)分區的(de)(de)(de)方法還便(bian)于(yu)(yu)高(gao)效實現數(shu)(shu)據(ju)(ju)的(de)(de)(de)保留策略,只(zhi)要數(shu)(shu)據(ju)(ju)文件超過規定的(de)(de)(de)天(tian)數(shu)(shu)(系(xi)統配置參數(shu)(shu) keep),將被自動刪除(chu)。而且不同的(de)(de)(de)時(shi)(shi)間段(duan)(duan)可(ke)以(yi)存(cun)放于(yu)(yu)不同的(de)(de)(de)路徑(jing)和(he)存(cun)儲介(jie)質,以(yi)便(bian)于(yu)(yu)大(da)數(shu)(shu)據(ju)(ju)的(de)(de)(de)冷熱管理,實現多級存(cun)儲。

總的來說,TDengine 是通過 vnode 以及時間兩個維度,對大數據進行切分,便于并行高效的管理(li),實現水平擴展。

負載均衡

每個(ge) dnode 都定時向 mnode(虛擬管理節點(dian))報告其狀態(包括硬(ying)盤(pan)空間、內存(cun)大(da)小、CPU、網絡、虛擬節點(dian)個(ge)數等),因此 mnode 了解整(zheng)(zheng)個(ge)集群的狀態。基于整(zheng)(zheng)體狀態,當 mnode 發現某個(ge)dnode負載過重,它會(hui)將(jiang)dnode 上的一個(ge)或多(duo)個(ge) vnode 挪(nuo)到(dao)其他 dnode。在挪(nuo)動過程(cheng)中,對外(wai)服(fu)務(wu)繼續進(jin)行,數據插入(ru)、查詢(xun)和計算操作(zuo)都不受(shou)影響。

如(ru)(ru)(ru)果(guo)(guo) mnode 一(yi)段時(shi)間沒(mei)有收到(dao) dnode 的狀態報(bao)告,mnode 會認為這個 dnode 已經離(li)線。如(ru)(ru)(ru)果(guo)(guo)離(li)線時(shi)間超過一(yi)定(ding)時(shi)長(時(shi)長由配置參數(shu) offlineThreshold 決定(ding)),該 dnode 將被 mnode 強制剔除出集群。該dnode 上的 vnodes 如(ru)(ru)(ru)果(guo)(guo)副(fu)(fu)本(ben)(ben)數(shu)大(da)于 1,系(xi)統(tong)將自(zi)(zi)動在其他(ta) dnode 上創建新的副(fu)(fu)本(ben)(ben),以保證數(shu)據的副(fu)(fu)本(ben)(ben)數(shu)。如(ru)(ru)(ru)果(guo)(guo)該 dnode 上還有 mnode, 而且 mnode 的副(fu)(fu)本(ben)(ben)數(shu)大(da)于1,系(xi)統(tong)也(ye)將自(zi)(zi)動在其他(ta) dnode 上創建新的 mnode, 以保證 mnode 的副(fu)(fu)本(ben)(ben)數(shu)。

當新(xin)的數據節點被添(tian)加進集群,因(yin)為新(xin)的計(ji)算和存(cun)儲被添(tian)加進來(lai),系統也將自動啟動負載均衡(heng)流(liu)程(cheng)。

負(fu)載均衡(heng)過程(cheng)無(wu)需任何(he)人工干(gan)預(yu),應(ying)用也(ye)無(wu)需重啟,將自動連接新的節(jie)點(dian),完全透明。

提示:負載均衡由參數 balance 控制,決定開啟/關閉自動負載均衡。

數據寫入與復制流程

如果一個(ge)數(shu)據庫(ku)有 N 個(ge)副本,那一個(ge)虛擬節點組就(jiu)有 N 個(ge)虛擬節點,但(dan)是(shi)只有一個(ge)是(shi) master,其他(ta)都(dou)是(shi) slave。當(dang)應用將(jiang)新的(de)記錄(lu)寫(xie)(xie)入系統(tong)時,只有 master vnode 能接受寫(xie)(xie)的(de)請求。如果 slave vnode 收到寫(xie)(xie)的(de)請求,系統(tong)將(jiang)通(tong)知(zhi) taosc 需(xu)要重新定向。

Master Vnode 寫入流程

Master Vnode 遵(zun)循下(xia)面(mian)的寫入流(liu)程(cheng):

TDengine Master寫入流程

圖 3 TDengine Master 寫入流程
  1. master vnode 收到應用的數據插入請求,驗證OK,進入下一步;
  2. 如果系統配置參數 walLevel 大于 0,vnode 將把該請求的原始數據包寫入數據庫日志文件 WAL。如果 walLevel 設置為 2,而且 fsync 設置為 0,TDengine 還將 WAL 數據立即落盤,以保證即使宕機,也能從數據庫日志文件中恢復數據,避免數據的丟失;
  3. 如果有多個副本,vnode 將把數據包轉發給同一虛擬節點組內的 slave vnodes, 該轉發包帶有數據的版本號(version);
  4. 寫入內存,并將記錄加入到 skip list;
  5. master vnode 返回確認信息給應用,表示寫入成功。
  6. 如果第 2、3、4 步中任何一步失敗,將直接返回錯誤給應用。

Slave Vnode 寫入流程

對(dui)于 slave vnode,寫入流程是:

TDengine Slave 寫入流程

圖 4 TDengine Slave 寫入流程
  1. slave vnode 收到 Master vnode 轉發了的數據插入請求。檢查 last version 是否與 master 一致,如果一致,進入下一步。如果不一致,需要進入同步狀態。
  2. 如果系統配置參數 walLevel 大于 0,vnode 將把該請求的原始數據包寫入數據庫日志文件 WAL。如果 walLevel 設置為 2,而且 fsync 設置為 0,TDengine 還將 WAL 數據立即落盤,以保證即使宕機,也能從數據庫日志文件中恢復數據,避免數據的丟失。
  3. 寫入內存,更新內存中的 skip list。

與 master vnode 相比,slave vnode 不存(cun)在(zai)轉(zhuan)發(fa)環(huan)節,也不存(cun)在(zai)回(hui)復確認環(huan)節,少(shao)了兩步。但寫內存(cun)與 WAL 是完全一樣(yang)的。

主從選擇

Vnode 會保持一個(ge)數(shu)據(ju)(ju)版本號(version),對內存數(shu)據(ju)(ju)進行持久化存儲(chu)時(shi),對該版本號也進行持久化存儲(chu)。每個(ge)數(shu)據(ju)(ju)更新操作,無論是采集的時(shi)序(xu)數(shu)據(ju)(ju)還是元數(shu)據(ju)(ju),這(zhe)個(ge)版本號將(jiang)增加 1。

一(yi)個 vnode 啟動時(shi),角(jiao)色(master、slave) 是不定的,數據是處于未同步(bu)狀態,它需要與(yu)虛擬節點組內其他節點建立(li) TCP 連接,并互相交(jiao)換(huan) status,其中包括 version 和自己(ji)的角(jiao)色。通過 status 的交(jiao)換(huan),系統進入選主流程(cheng),規則如下(xia):

  1. 如果只有一個副本,該副本永遠就是 master
  2. 所有副本都在線時,版本最高的被選為 master
  3. 在線的虛擬節點數過半,而且有虛擬節點是 slave 的話,該虛擬節點自動成為 master
  4. 對于 2 和 3,如果多個虛擬節點滿足成為 master 的要求,那么虛擬節點組的節點列表里,最前面的選為 master

更多的關于數據復制的流程,請見TDengine 2.0 數據復制模塊設計

同步復制

對于(yu)數(shu)(shu)據一(yi)致性要求更高的(de)場景,異步數(shu)(shu)據復制無法(fa)滿足要求,因(yin)(yin)為有(you)極小的(de)概率丟失數(shu)(shu)據,因(yin)(yin)此 TDengine 提供(gong)同步復制的(de)機(ji)制供(gong)用(yong)(yong)戶選擇。在(zai)創建(jian)數(shu)(shu)據庫(ku)時,除指(zhi)定(ding)副(fu)(fu)本(ben)數(shu)(shu) replica 之外,用(yong)(yong)戶還(huan)需(xu)要指(zhi)定(ding)新(xin)的(de)參數(shu)(shu) quorum。如果 quorum 大于(yu)1,它表示每次(ci)master轉發給副(fu)(fu)本(ben)時,需(xu)要等(deng)待 quorum-1 個(ge)回復確(que)認,才能(neng)通(tong)知應(ying)用(yong)(yong),數(shu)(shu)據在(zai) slave 已(yi)經寫(xie)入成功。如果在(zai)一(yi)定(ding)的(de)時間內(nei),得不到(dao) quorum-1 個(ge)回復確(que)認,master vnode 將返回錯誤給應(ying)用(yong)(yong)。

采用(yong)同(tong)(tong)步復(fu)制(zhi),系統的性能會有所(suo)下降,而且(qie) latency 會增加。因為元數(shu)據(ju)(ju)要(yao)強一致(zhi),mnode 之間(jian)的數(shu)據(ju)(ju)同(tong)(tong)步缺省就(jiu)是采用(yong)的同(tong)(tong)步復(fu)制(zhi)。

緩存與持久化

緩存

TDengine 采用(yong)時間(jian)驅(qu)動緩存(cun)(cun)管(guan)理策略(lve)(First-In-First-Out,FIFO),又稱為寫(xie)驅(qu)動的(de)緩存(cun)(cun)管(guan)理機制。這種策略(lve)有別于讀驅(qu)動的(de)數(shu)據緩存(cun)(cun)模(mo)式(Least-Recent-Used,LRU),直接將(jiang)(jiang)最近寫(xie)入(ru)的(de)數(shu)據保存(cun)(cun)在系(xi)統的(de)緩存(cun)(cun)中(zhong)。當緩存(cun)(cun)達(da)到臨界值的(de)時候,將(jiang)(jiang)最早的(de)數(shu)據批量寫(xie)入(ru)磁盤。一般意義(yi)上來(lai)說(shuo),對(dui)于物聯網(wang)數(shu)據的(de)使用(yong),用(yong)戶最為關心(xin)的(de)是剛(gang)產生(sheng)的(de)數(shu)據,即當前狀(zhuang)態。TDengine 充分(fen)利用(yong)這一特性,將(jiang)(jiang)最近到達(da)的(de)(當前狀(zhuang)態)數(shu)據保存(cun)(cun)在緩存(cun)(cun)中(zhong)。

TDengine 通過查詢函數向用戶提供毫秒級的數據獲取能力。直接將最近到達的數據保存在緩存中,可以更加快速地響應用戶針對最近一條或一批數據的查詢分析,整體上提供更快的數據庫查詢響應能力。從這個意義上來說,可通過設置合適的配置參數將 TDengine 作為數據緩存來使用,而不需要再部署 Redis 或其他額外的緩存系統,可有效(xiao)地簡化系統架構,降低運(yun)維的(de)(de)成(cheng)本。需(xu)要注意的(de)(de)是,TDengine 重啟以后系統的(de)(de)緩(huan)(huan)(huan)存將被清空(kong),之前緩(huan)(huan)(huan)存的(de)(de)數(shu)據(ju)均會被批量(liang)寫入磁盤,緩(huan)(huan)(huan)存的(de)(de)數(shu)據(ju)將不會像(xiang)專門(men)的(de)(de) key-value 緩(huan)(huan)(huan)存系統再將之前緩(huan)(huan)(huan)存的(de)(de)數(shu)據(ju)重新(xin)加載到(dao)緩(huan)(huan)(huan)存中。

每(mei)個(ge) vnode 有(you)(you)自己獨立的(de)(de)內(nei)(nei)(nei)(nei)(nei)存(cun),而(er)且(qie)由(you)(you)多個(ge)固定(ding)(ding)大(da)小的(de)(de)內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)組成,不同 vnode 之間完全隔離。數(shu)據(ju)寫入時,類似(si)于日志的(de)(de)寫法,數(shu)據(ju)被順序(xu)追加寫入內(nei)(nei)(nei)(nei)(nei)存(cun),但每(mei)個(ge) vnode 維護有(you)(you)自己的(de)(de) skip list,便于迅速查(cha)找。當三(san)分之一(yi)以(yi)上的(de)(de)內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)寫滿時,啟動落盤操(cao)作,而(er)且(qie)后續寫的(de)(de)操(cao)作在新的(de)(de)內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)進(jin)行。這樣,一(yi)個(ge) vnode 里(li)有(you)(you)三(san)分之一(yi)內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)是(shi)保(bao)留(liu)有(you)(you)最近的(de)(de)數(shu)據(ju)的(de)(de),以(yi)達到緩存(cun)、快速查(cha)找的(de)(de)目(mu)的(de)(de)。一(yi)個(ge) vnode 的(de)(de)內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)的(de)(de)個(ge)數(shu)由(you)(you)配置參數(shu) blocks 決(jue)定(ding)(ding),內(nei)(nei)(nei)(nei)(nei)存(cun)塊(kuai)(kuai)的(de)(de)大(da)小由(you)(you)配置參數(shu) cache 決(jue)定(ding)(ding)。

持久化存儲

TDengine 采(cai)用數(shu)據(ju)(ju)(ju)(ju)(ju)驅(qu)動(dong)的(de)方式(shi)讓(rang)緩(huan)存(cun)中的(de)數(shu)據(ju)(ju)(ju)(ju)(ju)寫(xie)入硬盤(pan)進行(xing)持久化(hua)存(cun)儲(chu)。當 vnode 中緩(huan)存(cun)的(de)數(shu)據(ju)(ju)(ju)(ju)(ju)達到一定規模時(shi),為了不阻塞后續數(shu)據(ju)(ju)(ju)(ju)(ju)的(de)寫(xie)入,TDengine 也(ye)會拉(la)起(qi)落盤(pan)線程將緩(huan)存(cun)的(de)數(shu)據(ju)(ju)(ju)(ju)(ju)寫(xie)入持久化(hua)存(cun)儲(chu)。TDengine 在數(shu)據(ju)(ju)(ju)(ju)(ju)落盤(pan)時(shi)會打(da)開新的(de)數(shu)據(ju)(ju)(ju)(ju)(ju)庫日(ri)(ri)志文件,在落盤(pan)成(cheng)功后則會刪(shan)除老的(de)數(shu)據(ju)(ju)(ju)(ju)(ju)庫日(ri)(ri)志文件,避免日(ri)(ri)志文件無(wu)限(xian)制地(di)增長。

為充分利用(yong)時序數據(ju)特點,TDengine 將一個(ge) vnode 保存在(zai)持久化存儲(chu)的(de)數據(ju)切分成多個(ge)文件,每個(ge)文件只(zhi)保存固定天(tian)數的(de)數據(ju),這(zhe)個(ge)天(tian)數由(you)系統(tong)配置參數 days 決定。切分成多個(ge)文件后,給定查詢的(de)起(qi)止日期,無需任何(he)索(suo)引,就可以立即定位需要打(da)開哪些(xie)數據(ju)文件,大大加快讀取(qu)速度(du)。

對于采集的數(shu)據,一(yi)般有(you)保(bao)留時(shi)長(chang)(chang),這(zhe)個(ge)時(shi)長(chang)(chang)由系統(tong)配置(zhi)參數(shu) keep 決(jue)定。超(chao)過這(zhe)個(ge)設(she)置(zhi)天數(shu)的數(shu)據文件,將被系統(tong)自動刪除,釋放存儲空間(jian)。

給定 days 與 keep 兩個參數,一個典型工作狀態的 vnode 中總的數據文件數為:向上取整(keep/days)+1個(ge)。總的數(shu)據文件個(ge)數(shu)不(bu)宜過大,也(ye)不(bu)宜過小(xiao)。10到100以內合適。基于(yu)這(zhe)個(ge)原(yuan)則,可以設置合理的 days。目(mu)前的版本,參(can)數(shu) keep 可以修(xiu)改,但對于(yu)參(can)數(shu) days,一旦(dan)設置后,不(bu)可修(xiu)改。

在每(mei)個(ge)數(shu)(shu)(shu)據(ju)(ju)文件(jian)(jian)(jian)里,一張(zhang)表的(de)(de)數(shu)(shu)(shu)據(ju)(ju)是一塊一塊存儲的(de)(de)。一張(zhang)表可以有一到多個(ge)數(shu)(shu)(shu)據(ju)(ju)文件(jian)(jian)(jian)塊。在一個(ge)文件(jian)(jian)(jian)塊里,數(shu)(shu)(shu)據(ju)(ju)是列(lie)式存儲的(de)(de),占用的(de)(de)是一片連續的(de)(de)存儲空間,這樣大(da)大(da)提高讀(du)取(qu)速(su)(su)度。文件(jian)(jian)(jian)塊的(de)(de)大(da)小(xiao)由系統參(can)數(shu)(shu)(shu) maxRows (每(mei)塊最大(da)記錄條數(shu)(shu)(shu))決定,缺(que)省值為 4096。這個(ge)值不(bu)宜過(guo)大(da),也不(bu)宜過(guo)小(xiao)。過(guo)大(da),定位(wei)具體時間段的(de)(de)數(shu)(shu)(shu)據(ju)(ju)的(de)(de)搜(sou)索時間會變(bian)長(chang),影響(xiang)讀(du)取(qu)速(su)(su)度;過(guo)小(xiao),數(shu)(shu)(shu)據(ju)(ju)塊的(de)(de)索引太大(da),壓縮(suo)效率偏低,也影響(xiang)讀(du)取(qu)速(su)(su)度。

每(mei)個(ge)數(shu)(shu)據(ju)(ju)(ju)文件(jian)(.data 結(jie)尾)都有一(yi)(yi)(yi)個(ge)對(dui)應的(de)(de)索引(yin)文件(jian)(.head 結(jie)尾),該(gai)索引(yin)文件(jian)對(dui)每(mei)張(zhang)表(biao)都有一(yi)(yi)(yi)數(shu)(shu)據(ju)(ju)(ju)塊的(de)(de)摘要(yao)信息(xi),記(ji)(ji)錄(lu)(lu)了每(mei)個(ge)數(shu)(shu)據(ju)(ju)(ju)塊在數(shu)(shu)據(ju)(ju)(ju)文件(jian)中的(de)(de)偏(pian)移量,數(shu)(shu)據(ju)(ju)(ju)的(de)(de)起止時(shi)間等(deng)信息(xi),以幫(bang)助系統迅(xun)速(su)定(ding)位需要(yao)查找(zhao)的(de)(de)數(shu)(shu)據(ju)(ju)(ju)。每(mei)個(ge)數(shu)(shu)據(ju)(ju)(ju)文件(jian)還有一(yi)(yi)(yi)對(dui)應的(de)(de) last 文件(jian)(.last 結(jie)尾),該(gai)文件(jian)是為(wei)防止落(luo)盤(pan)時(shi)數(shu)(shu)據(ju)(ju)(ju)塊碎片化而設(she)計的(de)(de)。如果一(yi)(yi)(yi)張(zhang)表(biao)落(luo)盤(pan)的(de)(de)記(ji)(ji)錄(lu)(lu)條數(shu)(shu)沒有達到(dao)系統配置參(can)數(shu)(shu) minRows(每(mei)塊最小記(ji)(ji)錄(lu)(lu)條數(shu)(shu)),將被(bei)先存儲到(dao) last 文件(jian),等(deng)下次落(luo)盤(pan)時(shi),新落(luo)盤(pan)的(de)(de)記(ji)(ji)錄(lu)(lu)將與 last 文件(jian)的(de)(de)記(ji)(ji)錄(lu)(lu)進行合(he)并,再寫入數(shu)(shu)據(ju)(ju)(ju)文件(jian)。

數據(ju)(ju)寫(xie)入磁盤時,根(gen)據(ju)(ju)系統配置參數 comp 決定是否壓(ya)(ya)(ya)縮(suo)數據(ju)(ju)。TDengine 提供了(le)三種壓(ya)(ya)(ya)縮(suo)選項:無(wu)壓(ya)(ya)(ya)縮(suo)、一階(jie)(jie)(jie)段(duan)壓(ya)(ya)(ya)縮(suo)和(he)兩階(jie)(jie)(jie)段(duan)壓(ya)(ya)(ya)縮(suo),分別對應 comp 值(zhi)為 0、1 和(he) 2 的(de)情況。一階(jie)(jie)(jie)段(duan)壓(ya)(ya)(ya)縮(suo)根(gen)據(ju)(ju)數據(ju)(ju)的(de)類(lei)型進(jin)行了(le)相應的(de)壓(ya)(ya)(ya)縮(suo),壓(ya)(ya)(ya)縮(suo)算法包(bao)括 delta-delta 編(bian)碼、simple 8B 方法、zig-zag 編(bian)碼、LZ4 等算法。二階(jie)(jie)(jie)段(duan)壓(ya)(ya)(ya)縮(suo)在一階(jie)(jie)(jie)段(duan)壓(ya)(ya)(ya)縮(suo)的(de)基礎(chu)上又(you)用通用壓(ya)(ya)(ya)縮(suo)算法進(jin)行了(le)壓(ya)(ya)(ya)縮(suo),壓(ya)(ya)(ya)縮(suo)率更(geng)高。

多級存儲

說明:多級存儲功能僅企業版支持,從 2.0.16.0 版本開始(shi)提供。

在默認配置下(xia),TDengine 會將所有數(shu)據保存在 /var/lib/taos 目錄下(xia),而且每(mei)個 vnode 的(de)(de)數(shu)據文(wen)件保存在該目錄下(xia)的(de)(de)不同(tong)(tong)目錄。為擴(kuo)大存儲空間,盡量減少文(wen)件讀取的(de)(de)瓶頸(jing),提高數(shu)據吞吐率(lv) TDengine 可通過配置系統(tong)參數(shu) dataDir 讓多(duo)個掛(gua)載(zai)的(de)(de)硬盤被系統(tong)同(tong)(tong)時使(shi)用。

除此之外,TDengine 也提供了數據(ju)(ju)分(fen)級存(cun)儲(chu)的(de)(de)功能(neng),將(jiang)(jiang)不同(tong)時間段(duan)的(de)(de)數據(ju)(ju)存(cun)儲(chu)在(zai)掛載的(de)(de)不同(tong)介質(zhi)上的(de)(de)目(mu)錄里,從(cong)而實現不同(tong)“熱度(du)”的(de)(de)數據(ju)(ju)存(cun)儲(chu)在(zai)不同(tong)的(de)(de)存(cun)儲(chu)介質(zhi)上,充分(fen)利用存(cun)儲(chu),節約成(cheng)本(ben)。比(bi)如(ru),最(zui)新(xin)采集的(de)(de)數據(ju)(ju)需要經常訪(fang)問(wen),對硬盤(pan)的(de)(de)讀取性能(neng)要求高,那(nei)(nei)么用戶可(ke)以配置將(jiang)(jiang)這些數據(ju)(ju)存(cun)儲(chu)在(zai) SSD 盤(pan)上。超過一定期限的(de)(de)數據(ju)(ju),查詢需求量沒有那(nei)(nei)么高,那(nei)(nei)么可(ke)以存(cun)儲(chu)在(zai)相對便宜(yi)的(de)(de) HDD 盤(pan)上。

多級存(cun)儲支持3級,每級最多可配置 16 個掛載點。

TDengine 多級存儲(chu)配置方式如下(在配置文(wen)件(jian)/etc/taos/taos.cfg中):

dataDir [path] <level> <primary>
  • path: 掛載點的文件夾路徑
  • level: 介質存儲等級,取值為 0,1,2。
    0級存儲最新的數據,1級存儲次新的數據,2級存儲最老的數據,省略默認為 0。
    各級存儲之間的數據流向:0 級存儲 -> 1 級存儲 -> 2 級存儲。
    同一存儲等級可掛載多個硬盤,同一存儲等級上的數據文件分布在該存儲等級的所有硬盤上。
    需要說明的是,數據在不同級別的存儲介質上的移動,是由系統自動完成的,用戶無需干預。
  • primary: 是否為主掛載點,0(否)或 1(是),省略默認為 1。

在(zai)配置中,只允許一個主掛載點的(de)存在(zai)(level=0, primary=1),例(li)如采用如下的(de)配置方(fang)式:

dataDir /mnt/data1 0 1
dataDir /mnt/data2 0 0
dataDir /mnt/data3 1 0
dataDir /mnt/data4 1 0
dataDir /mnt/data5 2 0
dataDir /mnt/data6 2 0

注意:

  1. 多級存儲不允許跨級配置,合法的配置方案有:僅 0 級,僅 0 級+ 1 級,以及 0 級+ 1 級+ 2 級。而不允許只配置 level=0 和 level=2,而不配置 level=1。
  2. 禁止手動移除使用中的掛載盤,掛載盤目前不支持非本地的網絡盤。
  3. 多級存儲目前不支持刪除已經掛載的硬盤的功能。

數據查詢

TDengine 提供了(le)多種多樣針(zhen)對表和超(chao)級表的查(cha)(cha)詢(xun)(xun)處理(li)功能,除(chu)了(le)常規的聚合查(cha)(cha)詢(xun)(xun)之外(wai),還提供針(zhen)對時序數據的窗口查(cha)(cha)詢(xun)(xun)、統(tong)計聚合等功能。TDengine 的查(cha)(cha)詢(xun)(xun)處理(li)需要客戶端、vnode、mnode 節點協(xie)同完成。

單表查詢

SQL 語(yu)句的(de)解(jie)析(xi)和(he)校驗工(gong)作(zuo)在客戶(hu)端完成。解(jie)析(xi) SQL 語(yu)句并生成抽象(xiang)語(yu)法樹(Abstract Syntax Tree, AST),然后對其進行校驗和(he)檢查(cha)。以及向(xiang)管理節點(mnode)請求(qiu)查(cha)詢中指(zhi)定(ding)表的(de)元數據信息(table metadata)。

根據(ju)元數據(ju)信(xin)息(xi)中(zhong)的 End Point 信(xin)息(xi),將(jiang)查(cha)(cha)詢(xun)(xun)(xun)請求(qiu)(qiu)序列(lie)化后(hou)發送(song)到(dao)該(gai)表所在(zai)的數據(ju)節點(dnode)。dnode 接收到(dao)查(cha)(cha)詢(xun)(xun)(xun)請求(qiu)(qiu)后(hou),識別出該(gai)查(cha)(cha)詢(xun)(xun)(xun)請求(qiu)(qiu)指向的虛(xu)擬節點(vnode),將(jiang)消息(xi)轉發到(dao) vnode 的查(cha)(cha)詢(xun)(xun)(xun)執(zhi)行(xing)隊列(lie)。vnode 的查(cha)(cha)詢(xun)(xun)(xun)執(zhi)行(xing)線(xian)程建立基礎(chu)的查(cha)(cha)詢(xun)(xun)(xun)執(zhi)行(xing)環境,并立即返回該(gai)查(cha)(cha)詢(xun)(xun)(xun)請求(qiu)(qiu),同(tong)時開始執(zhi)行(xing)該(gai)查(cha)(cha)詢(xun)(xun)(xun)。

客戶端在獲取查(cha)詢(xun)(xun)結(jie)果的(de)時候,dnode 的(de)查(cha)詢(xun)(xun)執行隊列中的(de)工作(zuo)線(xian)程會(hui)等待 vnode 執行線(xian)程執行完成,才(cai)能將查(cha)詢(xun)(xun)結(jie)果返(fan)回到(dao)請求(qiu)的(de)客戶端。

按時間軸聚合、降采樣、插值

時(shi)序數(shu)(shu)據(ju)有(you)別于普通(tong)(tong)數(shu)(shu)據(ju)的顯著特征是每條(tiao)記錄均具有(you)時(shi)間戳,因此針對具有(you)時(shi)間戳的數(shu)(shu)據(ju)在(zai)時(shi)間軸上進行(xing)聚合是不同于普通(tong)(tong)數(shu)(shu)據(ju)庫的重(zhong)要功能。從(cong)這點上來看(kan),與流計(ji)算(suan)引擎的窗口查詢有(you)相似的地方。

在 TDengine 中引入關鍵詞 interval 來進(jin)行時(shi)(shi)間軸上固(gu)定長度時(shi)(shi)間窗口(kou)的切分,并按照時(shi)(shi)間窗口(kou)對(dui)數(shu)據(ju)進(jin)行聚合(he),對(dui)窗口(kou)范圍(wei)內的數(shu)據(ju)按需進(jin)行聚合(he)。例如:

SELECT COUNT(*) FROM d1001 INTERVAL(1h);

針對 d1001 設備采(cai)集的(de)(de)數據,按照(zhao)1小時(shi)的(de)(de)時(shi)間窗(chuang)口返回每小時(shi)存儲的(de)(de)記錄數量。

在需要連續(xu)獲得查(cha)詢結(jie)果(guo)的(de)應用場景下,如(ru)果(guo)給定的(de)時間(jian)區(qu)間(jian)存在數據(ju)缺失(shi),會(hui)導致該(gai)區(qu)間(jian)數據(ju)結(jie)果(guo)也丟(diu)失(shi)。TDengine 提(ti)供策略針對時間(jian)軸(zhou)聚(ju)合計(ji)算的(de)結(jie)果(guo)進行(xing)插(cha)(cha)值(zhi),通過使用關鍵詞(ci) fill 就能夠對時間(jian)軸(zhou)聚(ju)合結(jie)果(guo)進行(xing)插(cha)(cha)值(zhi)。例(li)如(ru):

SELECT COUNT(*) FROM d1001 WHERE ts >= '2017-7-14 00:00:00' AND ts < '2017-7-14 23:59:59' INTERVAL(1h) FILL(PREV);

針對 d1001 設備采集(ji)數(shu)據(ju)統(tong)計每小(xiao)(xiao)時(shi)記錄數(shu),如(ru)果某一個(ge)小(xiao)(xiao)時(shi)不存在數(shu)據(ju),則返(fan)回(hui)之(zhi)前一個(ge)小(xiao)(xiao)時(shi)的(de)統(tong)計數(shu)據(ju)。TDengine 提供前向插值(prev)、線性插值(linear)、NULL值填充(chong)(NULL)、特定值填充(chong)(value)。

多表聚合查詢

TDengine 對(dui)每(mei)(mei)個數(shu)據采(cai)(cai)集(ji)點(dian)單獨(du)建(jian)表(biao)(biao),但在實(shi)際應用(yong)(yong)中經常(chang)需要(yao)對(dui)不同的(de)采(cai)(cai)集(ji)點(dian)數(shu)據進(jin)行(xing)聚合(he)(he)。為高(gao)效的(de)進(jin)行(xing)聚合(he)(he)操作,TDengine 引入(ru)超(chao)級表(biao)(biao)(STable)的(de)概念。超(chao)級表(biao)(biao)用(yong)(yong)來代表(biao)(biao)一特(te)定(ding)類型的(de)數(shu)據采(cai)(cai)集(ji)點(dian),它是包含(han)多張(zhang)表(biao)(biao)的(de)表(biao)(biao)集(ji)合(he)(he),集(ji)合(he)(he)里每(mei)(mei)張(zhang)表(biao)(biao)的(de)模(mo)式(schema)完全(quan)一致,但每(mei)(mei)張(zhang)表(biao)(biao)都帶(dai)有自己的(de)靜(jing)態標簽,標簽可以(yi)有多個,可以(yi)隨時增(zeng)加、刪(shan)除和修改。應用(yong)(yong)可通過(guo)指定(ding)標簽的(de)過(guo)濾條件,對(dui)一個 STable 下的(de)全(quan)部(bu)或部(bu)分表(biao)(biao)進(jin)行(xing)聚合(he)(he)或統計操作,這(zhe)樣大大簡化(hua)應用(yong)(yong)的(de)開(kai)發。其具體流程如下圖(tu)所示:

多表聚合查詢原理圖

圖 5 多表聚合查詢原理圖
  1. 應用將一個查詢條件發往系統;
  2. taosc 將超級表的名字發往 meta node(管理節點);
  3. 管理節點將超級表所擁有的 vnode 列表發回 taosc;
  4. taosc 將計算的請求連同標簽過濾條件發往這些 vnode 對應的多個數據節點;
  5. 每個 vnode 先在內存里查找出自己節點里符合標簽過濾條件的表的集合,然后掃描存儲的時序數據,完成相應的聚合計算,將結果返回給 taosc;
  6. taosc 將多個數據節點返回的結果做最后的聚合,將其返回給應用。

由于 TDengine 在(zai) vnode 內將標簽(qian)數(shu)據(ju)(ju)與(yu)時序(xu)數(shu)據(ju)(ju)分(fen)離存儲,通(tong)過(guo)(guo)在(zai)內存里(li)過(guo)(guo)濾(lv)標簽(qian)數(shu)據(ju)(ju),先找到(dao)需要(yao)(yao)參(can)與(yu)聚(ju)合(he)操(cao)作(zuo)(zuo)的(de)表的(de)集(ji)合(he),將需要(yao)(yao)掃描的(de)數(shu)據(ju)(ju)集(ji)大(da)幅減少,大(da)幅提(ti)(ti)升(sheng)聚(ju)合(he)計算速度(du)。同時,由于數(shu)據(ju)(ju)分(fen)布在(zai)多個 vnode/dnode,聚(ju)合(he)計算操(cao)作(zuo)(zuo)在(zai)多個 vnode 里(li)并發進行,又(you)進一步提(ti)(ti)升(sheng)了聚(ju)合(he)的(de)速度(du)。 對普通(tong)表的(de)聚(ju)合(he)函數(shu)以及(ji)絕(jue)大(da)部分(fen)操(cao)作(zuo)(zuo)都適(shi)用(yong)于超(chao)級(ji)表,語法完(wan)全一樣,細節請看 TAOS SQL。

預計算

為(wei)有效提升查詢(xun)處(chu)(chu)理的(de)(de)性(xing)能,針對物聯(lian)網數據(ju)(ju)(ju)(ju)的(de)(de)不可更改(gai)的(de)(de)特(te)點,在數據(ju)(ju)(ju)(ju)塊頭部(bu)記錄該數據(ju)(ju)(ju)(ju)塊中存(cun)儲數據(ju)(ju)(ju)(ju)的(de)(de)統計(ji)(ji)(ji)信息:包(bao)括最大值(zhi)、最小(xiao)值(zhi)、和。我(wo)們稱之(zhi)為(wei)預(yu)計(ji)(ji)(ji)算單(dan)元。如果查詢(xun)處(chu)(chu)理涉(she)及整個數據(ju)(ju)(ju)(ju)塊的(de)(de)全部(bu)數據(ju)(ju)(ju)(ju),直接使用預(yu)計(ji)(ji)(ji)算結(jie)果,完全不需(xu)要(yao)讀取數據(ju)(ju)(ju)(ju)塊的(de)(de)內容。由于(yu)預(yu)計(ji)(ji)(ji)算數據(ju)(ju)(ju)(ju)量(liang)遠小(xiao)于(yu)磁盤上存(cun)儲的(de)(de)數據(ju)(ju)(ju)(ju)塊數據(ju)(ju)(ju)(ju)的(de)(de)大小(xiao),對于(yu)磁盤 I/O 為(wei)瓶頸的(de)(de)查詢(xun)處(chu)(chu)理,使用預(yu)計(ji)(ji)(ji)算結(jie)果可以極大地減小(xiao)讀取 I/O 壓(ya)力,加速查詢(xun)處(chu)(chu)理的(de)(de)流程(cheng)。預(yu)計(ji)(ji)(ji)算機制與 Postgre SQL 的(de)(de)索引 BRIN(block range index)有異(yi)曲同工之(zhi)妙。