六月婷婷AV,国产偷窥猎奇福利二区,日韩三级片。,好吊色网站,日韩成人中文在线视频,国产亚洲午夜啪啪,亚洲欧美另类国产精品,国产成人av1,任你艹在线观看

數(shù)據(jù)模型和整體架構(gòu)

數(shù)據(jù)模型

物聯(lián)網(wǎng)典型場景

在典型的物聯(lián)網(wǎng)、車聯(lián)網(wǎng)、運維監(jiān)測場景中,往往有多種不同類型的數(shù)據(jù)采集設(shè)備,采集一個到多個不同的物理量。而同一種采集設(shè)備類型,往往又有多個具體的采集設(shè)備分布在不同的地點。大數(shù)據(jù)處理系統(tǒng)就是要將各種采集的數(shù)據(jù)匯總,然后進行計算和分析。對于同一類設(shè)備,其采集的數(shù)據(jù)都是很規(guī)則的。以智能電表為例,假設(shè)每個智能電表采集電流、電壓、相位三個量,其采集的數(shù)據(jù)類似如下的表格:

設(shè)備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:智能電表數(shù)據(jù)示例

每一條記錄都有設(shè)備 ID,時間戳,采集的物理量(如上圖中的電流、電壓、相位),還有與每個設(shè)備相關(guān)的靜態(tài)標簽(如上述表1中的位置 Location 和分組 groupId)。每個設(shè)備是受外界的觸發(fā),或按照設(shè)定的周期采集數(shù)據(jù)。采集的數(shù)據(jù)點是時序的,是一個數(shù)據(jù)流。

數(shù)據(jù)特征

除時序特征外,仔細研究發(fā)現(xiàn),物聯(lián)網(wǎng)、車聯(lián)網(wǎng)、運維監(jiān)測類數(shù)據(jù)還具有很多其他明顯的特征:

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

充分利用上述特征,TDengine 采取了經(jīng)特殊優(yōu)化的存儲和計算設(shè)計來處理時序數(shù)據(jù),它將系統(tǒng)處理能力顯著提高,同時大幅降低了系統(tǒng)運維的復(fù)雜度。

關(guān)系型數(shù)據(jù)庫模型

因為采集的數(shù)據(jù)一般是結(jié)構(gòu)化數(shù)據(jù),同時為降低學習門檻,TDengine 采用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫模型管理數(shù)據(jù)。因此用戶需要先創(chuàng)建庫,然后創(chuàng)建表,之后才能插入或查詢數(shù)據(jù)。TDengine 采用的是結(jié)構(gòu)化存儲,而不是 NoSQL 的 key-value 存儲。

一個數(shù)據(jù)采集點一張表

為充分利用其數(shù)據(jù)的時序性和其他數(shù)據(jù)特點,TDengine 要求對每個數(shù)據(jù)采集點單獨建表(比如有一千萬個智能電表,就需創(chuàng)建一千萬張表,上述表格中的 d1001, d1002, d1003, d1004 都需單獨建表),用來存儲這個采集點所采集的時序數(shù)據(jù)。這種設(shè)計有幾大優(yōu)點:

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

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

TDengine 建議用數(shù)據(jù)采集點的名字(如上表中的 D1001)來做表名。每個數(shù)據(jù)采集點可能同時采集多個物理量(如上表中的 current, voltage, phase),每個物理量對應(yīng)一張表中的一列,數(shù)據(jù)類型可以是整型、浮點型、字符串等。除此之外,表的第一列必須是時間戳,即數(shù)據(jù)類型為 timestamp。對采集的數(shù)據(jù),TDengine 將自動按照時間戳建立索引,但對采集的物理量不建任何索引。數(shù)據(jù)用列式存儲方式保存。

超級表:同一類型數(shù)據(jù)采集點的集合

由于一個數(shù)據(jù)采集點一張表,導(dǎo)致表的數(shù)量巨增,難以管理,而且應(yīng)用經(jīng)常需要做采集點之間的聚合操作,聚合的操作也變得復(fù)雜起來。為解決這個問題,TDengine 引入超級表(Super Table,簡稱為 STable)的概念。

超級表是指某一特定類型的數(shù)據(jù)采集點的集合。同一類型的數(shù)據(jù)采集點,其表的結(jié)構(gòu)是完全一樣的,但每個表(數(shù)據(jù)采集點)的靜態(tài)屬性(標簽)是不一樣的。描述一個超級表(某一特定類型的數(shù)據(jù)采集點的集合),除需要定義采集量的表結(jié)構(gòu)之外,還需要定義其標簽的 schema,標簽的數(shù)據(jù)類型可以是整數(shù)、浮點數(shù)、字符串,標簽可以有多個,可以事后增加、刪除或修改。如果整個系統(tǒng)有 N 個不同類型的數(shù)據(jù)采集點,就需要建立 N 個超級表。

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

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

集群與基本邏輯單元

TDengine 的設(shè)計是基于單個硬件、軟件系統(tǒng)不可靠,基于任何單臺計算機都無法提供足夠計算能力和存儲能力處理海量數(shù)據(jù)的假設(shè)進行設(shè)計的。因此 TDengine 從研發(fā)的第一天起,就按照分布式高可靠架構(gòu)進行設(shè)計,是支持水平擴展的,這樣任何單臺或多臺服務(wù)器發(fā)生硬件故障或軟件錯誤都不影響系統(tǒng)的可用性和可靠性。同時,通過節(jié)點虛擬化并輔以自動化負載均衡技術(shù),TDengine 能最高效率地利用異構(gòu)集群中的計算和存儲資源降低硬件投資。

主要邏輯單元

TDengine 分布式架構(gòu)的邏輯結(jié)構(gòu)圖如下:

TDengine架構(gòu)示意圖

圖 1 TDengine架構(gòu)示意圖

一個完整的 TDengine 系統(tǒng)是運行在一到多個物理節(jié)點上的,邏輯上,它包含數(shù)據(jù)節(jié)點(dnode)、TDengine 應(yīng)用驅(qū)動(taosc)以及應(yīng)用(app)。系統(tǒng)中存在一到多個數(shù)據(jù)節(jié)點,這些數(shù)據(jù)節(jié)點組成一個集群(cluster)。應(yīng)用通過 taosc 的 API 與 TDengine 集群進行互動。下面對每個邏輯單元進行簡要介紹。

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

數(shù)據(jù)節(jié)點(dnode): dnode 是 TDengine 服務(wù)器側(cè)執(zhí)行代碼 taosd 在物理節(jié)點上的一個運行實例,一個工作的系統(tǒng)必須有至少一個數(shù)據(jù)節(jié)點。dnode 包含零到多個邏輯的虛擬節(jié)點(vnode),零或者至多一個邏輯的管理節(jié)點(mnode)。dnode 在系統(tǒng)中的唯一標識由實例的 End Point (EP)決定。EP 是 dnode 所在物理節(jié)點的 FQDN (Fully Qualified Domain Name)和系統(tǒng)所配置的網(wǎng)絡(luò)端口號(Port)的組合。通過配置不同的端口,一個物理節(jié)點(一臺物理機、虛擬機或容器)可以運行多個實例,或有多個數(shù)據(jù)節(jié)點。

虛擬節(jié)點(vnode): 為更好的支持數(shù)據(jù)分片、負載均衡,防止數(shù)據(jù)過熱或傾斜,數(shù)據(jù)節(jié)點被虛擬化成多個虛擬節(jié)點(vnode,圖中 V2, V3, V4等)。每個 vnode 都是一個相對獨立的工作單元,是時序數(shù)據(jù)存儲的基本單元,具有獨立的運行線程、內(nèi)存空間與持久化存儲的路徑。一個 vnode 包含一定數(shù)量的表(數(shù)據(jù)采集點)。當創(chuàng)建一張新表時,系統(tǒng)會檢查是否需要創(chuàng)建新的 vnode。一個數(shù)據(jù)節(jié)點上能創(chuàng)建的 vnode 的數(shù)量取決于該數(shù)據(jù)節(jié)點所在物理節(jié)點的硬件資源。一個 vnode 只屬于一個 DB,但一個 DB 可以有多個 vnode。一個 vnode 除存儲的時序數(shù)據(jù)外,也保存有所包含的表的 schema、標簽值等。一個虛擬節(jié)點由所屬的數(shù)據(jù)節(jié)點的EP,以及所屬的 VGroup ID 在系統(tǒng)內(nèi)唯一標識,由管理節(jié)點創(chuàng)建并管理。

管理節(jié)點(mnode): 一個虛擬的邏輯單元,負責所有數(shù)據(jù)節(jié)點運行狀態(tài)的監(jiān)控和維護,以及節(jié)點之間的負載均衡(圖中 M)。同時,管理節(jié)點也負責元數(shù)據(jù)(包括用戶、數(shù)據(jù)庫、表、靜態(tài)標簽等)的存儲和管理,因此也稱為 Meta Node。TDengine 集群中可配置多個(最多不超過 3 個) mnode,它們自動構(gòu)建成為一個虛擬管理節(jié)點組(圖中 M0, M1, M2)。mnode 間采用 master/slave 的機制進行管理,而且采取強一致方式進行數(shù)據(jù)同步, 任何數(shù)據(jù)更新操作只能在 Master 上進行。mnode 集群的創(chuàng)建由系統(tǒng)自動完成,無需人工干預(yù)。每個 dnode 上至多有一個 mnode,由所屬的數(shù)據(jù)節(jié)點的EP來唯一標識。每個 dnode 通過內(nèi)部消息交互自動獲取整個集群中所有 mnode 所在的 dnode 的EP。

虛擬節(jié)點組(VGroup): 不同數(shù)據(jù)節(jié)點上的 vnode 可以組成一個虛擬節(jié)點組(vnode group)來保證系統(tǒng)的高可靠。虛擬節(jié)點組內(nèi)采取 master/slave 的方式進行管理。寫操作只能在 master vnode 上進行,系統(tǒng)采用異步復(fù)制的方式將數(shù)據(jù)同步到 slave vnode,這樣確保了一份數(shù)據(jù)在多個物理節(jié)點上有拷貝。一個 vgroup 里虛擬節(jié)點個數(shù)就是數(shù)據(jù)的副本數(shù)。如果一個 DB 的副本數(shù)為 N,系統(tǒng)必須有至少 N 數(shù)據(jù)節(jié)點。副本數(shù)在創(chuàng)建DB時通過參數(shù) replica 可以指定,缺省為 1。使用 TDengine 的多副本特性,可以不再需要昂貴的磁盤陣列等存儲設(shè)備,就可以獲得同樣的數(shù)據(jù)高可靠性。虛擬節(jié)點組由管理節(jié)點創(chuàng)建、管理,并且由管理節(jié)點分配一個系統(tǒng)唯一的 ID,VGroup ID。如果兩個虛擬節(jié)點的 vnode group ID 相同,說明他們屬于同一個組,數(shù)據(jù)互為備份。虛擬節(jié)點組里虛擬節(jié)點的個數(shù)是可以動態(tài)改變的,容許只有一個,也就是沒有數(shù)據(jù)復(fù)制。VGroup ID 是永遠不變的,即使一個虛擬節(jié)點組被刪除,它的ID也不會被收回重復(fù)利用。

TAOSC: taosc 是 TDengine 給應(yīng)用提供的驅(qū)動程序(driver),負責處理應(yīng)用與集群的接口交互,提供 C/C++ 語言原生接口,內(nèi)嵌于 JDBC、C#、Python、Go、Node.js 語言連接庫里。應(yīng)用都是通過 taosc 而不是直接連接集群中的數(shù)據(jù)節(jié)點與整個集群進行交互的。這個模塊負責獲取并緩存元數(shù)據(jù);將插入、查詢等請求轉(zhuǎn)發(fā)到正確的數(shù)據(jù)節(jié)點;在把結(jié)果返回給應(yīng)用時,還需要負責最后一級的聚合、排序、過濾等操作。對于 JDBC、C/C++、C#、Python、Go、Node.js 接口而言,這個模塊是在應(yīng)用所處的物理節(jié)點上運行。同時,為支持全分布式的 RESTful 接口,taosc 在 TDengine 集群的每個 dnode 上都有一運行實例。

節(jié)點之間的通訊

通訊方式:TDengine 系統(tǒng)的各個數(shù)據(jù)節(jié)點之間,以及應(yīng)用驅(qū)動與各數(shù)據(jù)節(jié)點之間的通訊是通過 TCP/UDP 進行的。因為考慮到物聯(lián)網(wǎng)場景,數(shù)據(jù)寫入的包一般不大,因此 TDengine 除采用 TCP 做傳輸之外,還采用 UDP 方式,因為 UDP 更加高效,而且不受連接數(shù)的限制。TDengine 實現(xiàn)了自己的超時、重傳、確認等機制,以確保 UDP 的可靠傳輸。對于數(shù)據(jù)量不到15K的數(shù)據(jù)包,采取 UDP 的方式進行傳輸,超過 15K 的,或者是查詢類的操作,自動采取 TCP 的方式進行傳輸。同時,TDengine 根據(jù)配置和數(shù)據(jù)包,會自動對數(shù)據(jù)進行壓縮/解壓縮,數(shù)字簽名/認證等處理。對于數(shù)據(jù)節(jié)點之間的數(shù)據(jù)復(fù)制,只采用 TCP 方式進行數(shù)據(jù)傳輸。

FQDN配置:一個數(shù)據(jù)節(jié)點有一個或多個 FQDN,可以在系統(tǒng)配置文件 taos.cfg 通過參數(shù)"fqdn"進行指定,如果沒有指定,系統(tǒng)將自動獲取計算機的 hostname 作為其 FQDN。如果節(jié)點沒有配置 FQDN,可以直接將該節(jié)點的配置參數(shù) fqdn 設(shè)置為它的IP地址。但不建議使用 IP,因為 IP 地址可變,一旦變化,將讓集群無法正常工作。一個數(shù)據(jù)節(jié)點的 EP(End Point) 由 FQDN + Port 組成。采用 FQDN,需要保證 DNS 服務(wù)正常工作,或者在節(jié)點以及應(yīng)用所在的節(jié)點配置好 hosts 文件。另外,這個參數(shù)值的長度需要控制在 96 個字符以內(nèi)。

端口配置:一個數(shù)據(jù)節(jié)點對外的端口由 TDengine 的系統(tǒng)配置參數(shù) serverPort 決定,對集群內(nèi)部通訊的端口是 serverPort+5。為支持多線程高效的處理 UDP 數(shù)據(jù),每個對內(nèi)和對外的 UDP 連接,都需要占用5個連續(xù)的端口。

  • 集群內(nèi)數(shù)據(jù)節(jié)點之間的數(shù)據(jù)復(fù)制操作占用一個 TCP 端口,是 serverPort+10。
  • 集群數(shù)據(jù)節(jié)點對外提供 RESTful 服務(wù)占用一個 TCP 端口,是 serverPort+11。
  • 集群內(nèi)數(shù)據(jù)節(jié)點與 Arbitrator 節(jié)點之間通訊占用一個 TCP 端口,是 serverPort+12。

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

集群對外連接:TDengine 集群可以容納單個、多個甚至幾千個數(shù)據(jù)節(jié)點。應(yīng)用只需要向集群中任何一個數(shù)據(jù)節(jié)點發(fā)起連接即可,連接需要提供的網(wǎng)絡(luò)參數(shù)是一數(shù)據(jù)節(jié)點的 End Point(FQDN加配置的端口號)。通過命令行CLI啟動應(yīng)用 taos 時,可以通過選項-h來指定數(shù)據(jù)節(jié)點的 FQDN, -P 來指定其配置的端口號,如果端口不配置,將采用 TDengine 的系統(tǒng)配置參數(shù) serverPort。

集群內(nèi)部通訊:各個數(shù)據(jù)節(jié)點之間通過 TCP/UDP 進行連接。一個數(shù)據(jù)節(jié)點啟動時,將獲取 mnode 所在的 dnode 的 EP 信息,然后與系統(tǒng)中的 mnode 建立起連接,交換信息。獲取 mnode 的 EP 信息有三步:

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

獲取 mnode EP 列表后,數(shù)據(jù)節(jié)點發(fā)起連接,如果連接成功,則成功加入進工作的集群,如果不成功,則嘗試 mnode EP 列表中的下一個。如果都嘗試了,但連接都仍然失敗,則休眠幾秒后,再進行嘗試。

MNODE的選擇:TDengine 邏輯上有管理節(jié)點,但沒有單獨的執(zhí)行代碼,服務(wù)器側(cè)只有一套執(zhí)行代碼 taosd。那么哪個數(shù)據(jù)節(jié)點會是管理節(jié)點呢?這是系統(tǒng)自動決定的,無需任何人工干預(yù)。原則如下:一個數(shù)據(jù)節(jié)點啟動時,會檢查自己的 End Point, 并與獲取的 mnode EP List 進行比對,如果在其中,該數(shù)據(jù)節(jié)點認為自己應(yīng)該啟動 mnode 模塊,成為 mnode。如果自己的 EP 不在 mnode EP List 里,則不啟動 mnode 模塊。在系統(tǒng)的運行過程中,由于負載均衡、宕機等原因,mnode 有可能遷移至新的 dnode,但一切都是透明的,無需人工干預(yù),配置參數(shù)的修改,是 mnode 自己根據(jù)資源做出的決定。

新數(shù)據(jù)節(jié)點的加入:系統(tǒng)有了一個數(shù)據(jù)節(jié)點后,就已經(jīng)成為一個工作的系統(tǒng)。添加新的節(jié)點進集群時,有兩個步驟,第一步:使用 TDengine CLI 連接到現(xiàn)有工作的數(shù)據(jù)節(jié)點,然后用命令"create dnode"將新的數(shù)據(jù)節(jié)點的 End Point 添加進去; 第二步:在新的數(shù)據(jù)節(jié)點的系統(tǒng)配置參數(shù)文件 taos.cfg 里,將 firstEp, secondEp 參數(shù)設(shè)置為現(xiàn)有集群中任意兩個數(shù)據(jù)節(jié)點的 EP 即可。具體添加的詳細步驟請見詳細的用戶手冊。這樣就把集群一步一步的建立起來。

重定向:無論是 dnode 還是 taosc,最先都是要發(fā)起與 mnode 的連接,但 mnode 是系統(tǒng)自動創(chuàng)建并維護的,因此對于用戶來說,并不知道哪個 dnode 在運行 mnode。TDengine 只要求向系統(tǒng)中任何一個工作的 dnode 發(fā)起連接即可。因為任何一個正在運行的 dnode,都維護有目前運行的 mnode EP List。當收到一個來自新啟動的 dnode 或 taosc 的連接請求,如果自己不是 mnode,則將 mnode EP List 回復(fù)給對方,taosc 或新啟動的 dnode 收到這個 list, 就重新嘗試建立連接。當 mnode EP List 發(fā)生改變,通過節(jié)點之間的消息交互,各個數(shù)據(jù)節(jié)點就很快獲取最新列表,并通知 taosc。

一個典型的消息流程

為解釋 vnode、mnode、taosc 和應(yīng)用之間的關(guān)系以及各自扮演的角色,下面對寫入數(shù)據(jù)這個典型操作的流程進行剖析。

TDengine典型的操作流程

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

對于第二和第三步,taosc 啟動時,并不知道 mnode 的 End Point,因此會直接向配置的集群對外服務(wù)的 End Point 發(fā)起請求。如果接收到該請求的 dnode 并沒有配置 mnode,該 dnode 會在回復(fù)的消息中告知mnode EP 列表,這樣 taosc 會重新向新的 mnode 的 EP 發(fā)出獲取 meta-data 的請求。

對于第四和第五步,沒有緩存的情況下,taosc 無法知道虛擬節(jié)點組里誰是 master,就假設(shè)第一個 vnodeID 就是 master,向它發(fā)出請求。如果接收到請求的 vnode 并不是 master,它會在回復(fù)中告知誰是 master,這樣 taosc 就向建議的 master vnode 發(fā)出請求。一旦得到插入成功的回復(fù),taosc 會緩存 master 節(jié)點的信息。

上述是插入數(shù)據(jù)的流程,查詢、計算的流程也完全一致。taosc 把這些復(fù)雜的流程全部封裝屏蔽了,對于應(yīng)用來說無感知也無需任何特別處理。

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

存儲模型與數(shù)據(jù)分區(qū)、分片

存儲模型

TDengine 存儲的數(shù)據(jù)包括采集的時序數(shù)據(jù)以及庫、表相關(guān)的元數(shù)據(jù)、標簽數(shù)據(jù)等,這些數(shù)據(jù)具體分為三部分:

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

與典型的 NoSQL 存儲模型相比,TDengine 將標簽數(shù)據(jù)與時序數(shù)據(jù)完全分離存儲,它具有兩大優(yōu)勢:

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

數(shù)據(jù)分片

對于海量的數(shù)據(jù)管理,為實現(xiàn)水平擴展,一般都需要采取分片(Sharding)分區(qū)(Partitioning)策略。TDengine 是通過 vnode 來實現(xiàn)數(shù)據(jù)分片的,通過一個時間段一個數(shù)據(jù)文件來實現(xiàn)時序數(shù)據(jù)分區(qū)的。

vnode(虛擬數(shù)據(jù)節(jié)點)負責為采集的時序數(shù)據(jù)提供寫入、查詢和計算功能。為便于負載均衡、數(shù)據(jù)恢復(fù)、支持異構(gòu)環(huán)境,TDengine 將一個數(shù)據(jù)節(jié)點根據(jù)其計算和存儲資源切分為多個 vnode。這些 vnode 的管理是TDengine 自動完成的,對應(yīng)用完全透明。

對于單獨一個數(shù)據(jù)采集點,無論其數(shù)據(jù)量多大,一個 vnode(或 vnode group, 如果副本數(shù)大于 1)有足夠的計算資源和存儲資源來處理(如果每秒生成一條 16 字節(jié)的記錄,一年產(chǎn)生的原始數(shù)據(jù)不到 0.5G),因此 TDengine 將一張表(一個數(shù)據(jù)采集點)的所有數(shù)據(jù)都存放在一個 vnode 里,而不會讓同一個采集點的數(shù)據(jù)分布到兩個或多個 dnode 上。而且一個 vnode 可存儲多個數(shù)據(jù)采集點(表)的數(shù)據(jù),一個 vnode 可容納的表的數(shù)目的上限為一百萬。設(shè)計上,一個 vnode 里所有的表都屬于同一個 DB。一個數(shù)據(jù)節(jié)點上,除非特殊配置,一個 DB 擁有的 vnode 數(shù)目不會超過系統(tǒng)核的數(shù)目。

創(chuàng)建 DB 時,系統(tǒng)并不會馬上分配資源。但當創(chuàng)建一張表時,系統(tǒng)將看是否有已經(jīng)分配的 vnode, 且該 vnode 是否有空余的表空間,如果有,立即在該有空位的 vnode 創(chuàng)建表。如果沒有,系統(tǒng)將從集群中,根據(jù)當前的負載情況,在一個 dnode 上創(chuàng)建一新的 vnode, 然后創(chuàng)建表。如果DB有多個副本,系統(tǒng)不是只創(chuàng)建一個 vnode,而是一個 vgroup (虛擬數(shù)據(jù)節(jié)點組)。系統(tǒng)對 vnode 的數(shù)目沒有任何限制,僅僅受限于物理節(jié)點本身的計算和存儲資源。

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

數(shù)據(jù)分區(qū)

TDengine 除 vnode 分片之外,還對時序數(shù)據(jù)按照時間段進行分區(qū)。每個數(shù)據(jù)文件只包含一個時間段的時序數(shù)據(jù),時間段的長度由 DB 的配置參數(shù) days 決定。這種按時間段分區(qū)的方法還便于高效實現(xiàn)數(shù)據(jù)的保留策略,只要數(shù)據(jù)文件超過規(guī)定的天數(shù)(系統(tǒng)配置參數(shù) keep),將被自動刪除。而且不同的時間段可以存放于不同的路徑和存儲介質(zhì),以便于大數(shù)據(jù)的冷熱管理,實現(xiàn)多級存儲。

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

負載均衡

每個 dnode 都定時向 mnode(虛擬管理節(jié)點)報告其狀態(tài)(包括硬盤空間、內(nèi)存大小、CPU、網(wǎng)絡(luò)、虛擬節(jié)點個數(shù)等),因此 mnode 了解整個集群的狀態(tài)。基于整體狀態(tài),當 mnode 發(fā)現(xiàn)某個dnode負載過重,它會將dnode 上的一個或多個 vnode 挪到其他 dnode。在挪動過程中,對外服務(wù)繼續(xù)進行,數(shù)據(jù)插入、查詢和計算操作都不受影響。

如果 mnode 一段時間沒有收到 dnode 的狀態(tài)報告,mnode 會認為這個 dnode 已經(jīng)離線。如果離線時間超過一定時長(時長由配置參數(shù) offlineThreshold 決定),該 dnode 將被 mnode 強制剔除出集群。該dnode 上的 vnodes 如果副本數(shù)大于 1,系統(tǒng)將自動在其他 dnode 上創(chuàng)建新的副本,以保證數(shù)據(jù)的副本數(shù)。如果該 dnode 上還有 mnode, 而且 mnode 的副本數(shù)大于1,系統(tǒng)也將自動在其他 dnode 上創(chuàng)建新的 mnode, 以保證 mnode 的副本數(shù)。

當新的數(shù)據(jù)節(jié)點被添加進集群,因為新的計算和存儲被添加進來,系統(tǒng)也將自動啟動負載均衡流程。

負載均衡過程無需任何人工干預(yù),應(yīng)用也無需重啟,將自動連接新的節(jié)點,完全透明。

提示:負載均衡由參數(shù) balance 控制,決定開啟/關(guān)閉自動負載均衡。

數(shù)據(jù)寫入與復(fù)制流程

如果一個數(shù)據(jù)庫有 N 個副本,那一個虛擬節(jié)點組就有 N 個虛擬節(jié)點,但是只有一個是 master,其他都是 slave。當應(yīng)用將新的記錄寫入系統(tǒng)時,只有 master vnode 能接受寫的請求。如果 slave vnode 收到寫的請求,系統(tǒng)將通知 taosc 需要重新定向。

Master Vnode 寫入流程

Master Vnode 遵循下面的寫入流程:

TDengine Master寫入流程

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

Slave Vnode 寫入流程

對于 slave vnode,寫入流程是:

TDengine Slave 寫入流程

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

與 master vnode 相比,slave vnode 不存在轉(zhuǎn)發(fā)環(huán)節(jié),也不存在回復(fù)確認環(huán)節(jié),少了兩步。但寫內(nèi)存與 WAL 是完全一樣的。

主從選擇

Vnode 會保持一個數(shù)據(jù)版本號(version),對內(nèi)存數(shù)據(jù)進行持久化存儲時,對該版本號也進行持久化存儲。每個數(shù)據(jù)更新操作,無論是采集的時序數(shù)據(jù)還是元數(shù)據(jù),這個版本號將增加 1。

一個 vnode 啟動時,角色(master、slave) 是不定的,數(shù)據(jù)是處于未同步狀態(tài),它需要與虛擬節(jié)點組內(nèi)其他節(jié)點建立 TCP 連接,并互相交換 status,其中包括 version 和自己的角色。通過 status 的交換,系統(tǒng)進入選主流程,規(guī)則如下:

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

更多的關(guān)于數(shù)據(jù)復(fù)制的流程,請見TDengine 2.0 數(shù)據(jù)復(fù)制模塊設(shè)計。

同步復(fù)制

對于數(shù)據(jù)一致性要求更高的場景,異步數(shù)據(jù)復(fù)制無法滿足要求,因為有極小的概率丟失數(shù)據(jù),因此 TDengine 提供同步復(fù)制的機制供用戶選擇。在創(chuàng)建數(shù)據(jù)庫時,除指定副本數(shù) replica 之外,用戶還需要指定新的參數(shù) quorum。如果 quorum 大于1,它表示每次master轉(zhuǎn)發(fā)給副本時,需要等待 quorum-1 個回復(fù)確認,才能通知應(yīng)用,數(shù)據(jù)在 slave 已經(jīng)寫入成功。如果在一定的時間內(nèi),得不到 quorum-1 個回復(fù)確認,master vnode 將返回錯誤給應(yīng)用。

采用同步復(fù)制,系統(tǒng)的性能會有所下降,而且 latency 會增加。因為元數(shù)據(jù)要強一致,mnode 之間的數(shù)據(jù)同步缺省就是采用的同步復(fù)制。

緩存與持久化

緩存

TDengine 采用時間驅(qū)動緩存管理策略(First-In-First-Out,F(xiàn)IFO),又稱為寫驅(qū)動的緩存管理機制。這種策略有別于讀驅(qū)動的數(shù)據(jù)緩存模式(Least-Recent-Used,LRU),直接將最近寫入的數(shù)據(jù)保存在系統(tǒng)的緩存中。當緩存達到臨界值的時候,將最早的數(shù)據(jù)批量寫入磁盤。一般意義上來說,對于物聯(lián)網(wǎng)數(shù)據(jù)的使用,用戶最為關(guān)心的是剛產(chǎn)生的數(shù)據(jù),即當前狀態(tài)。TDengine 充分利用這一特性,將最近到達的(當前狀態(tài))數(shù)據(jù)保存在緩存中。

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

每個 vnode 有自己獨立的內(nèi)存,而且由多個固定大小的內(nèi)存塊組成,不同 vnode 之間完全隔離。數(shù)據(jù)寫入時,類似于日志的寫法,數(shù)據(jù)被順序追加寫入內(nèi)存,但每個 vnode 維護有自己的 skip list,便于迅速查找。當三分之一以上的內(nèi)存塊寫滿時,啟動落盤操作,而且后續(xù)寫的操作在新的內(nèi)存塊進行。這樣,一個 vnode 里有三分之一內(nèi)存塊是保留有最近的數(shù)據(jù)的,以達到緩存、快速查找的目的。一個 vnode 的內(nèi)存塊的個數(shù)由配置參數(shù) blocks 決定,內(nèi)存塊的大小由配置參數(shù) cache 決定。

持久化存儲

TDengine 采用數(shù)據(jù)驅(qū)動的方式讓緩存中的數(shù)據(jù)寫入硬盤進行持久化存儲。當 vnode 中緩存的數(shù)據(jù)達到一定規(guī)模時,為了不阻塞后續(xù)數(shù)據(jù)的寫入,TDengine 也會拉起落盤線程將緩存的數(shù)據(jù)寫入持久化存儲。TDengine 在數(shù)據(jù)落盤時會打開新的數(shù)據(jù)庫日志文件,在落盤成功后則會刪除老的數(shù)據(jù)庫日志文件,避免日志文件無限制地增長。

為充分利用時序數(shù)據(jù)特點,TDengine 將一個 vnode 保存在持久化存儲的數(shù)據(jù)切分成多個文件,每個文件只保存固定天數(shù)的數(shù)據(jù),這個天數(shù)由系統(tǒng)配置參數(shù) days 決定。切分成多個文件后,給定查詢的起止日期,無需任何索引,就可以立即定位需要打開哪些數(shù)據(jù)文件,大大加快讀取速度。

對于采集的數(shù)據(jù),一般有保留時長,這個時長由系統(tǒng)配置參數(shù) keep 決定。超過這個設(shè)置天數(shù)的數(shù)據(jù)文件,將被系統(tǒng)自動刪除,釋放存儲空間。

給定 days 與 keep 兩個參數(shù),一個典型工作狀態(tài)的 vnode 中總的數(shù)據(jù)文件數(shù)為:向上取整(keep/days)+1個。總的數(shù)據(jù)文件個數(shù)不宜過大,也不宜過小。10到100以內(nèi)合適?;谶@個原則,可以設(shè)置合理的 days。目前的版本,參數(shù) keep 可以修改,但對于參數(shù) days,一旦設(shè)置后,不可修改。

在每個數(shù)據(jù)文件里,一張表的數(shù)據(jù)是一塊一塊存儲的。一張表可以有一到多個數(shù)據(jù)文件塊。在一個文件塊里,數(shù)據(jù)是列式存儲的,占用的是一片連續(xù)的存儲空間,這樣大大提高讀取速度。文件塊的大小由系統(tǒng)參數(shù) maxRows (每塊最大記錄條數(shù))決定,缺省值為 4096。這個值不宜過大,也不宜過小。過大,定位具體時間段的數(shù)據(jù)的搜索時間會變長,影響讀取速度;過小,數(shù)據(jù)塊的索引太大,壓縮效率偏低,也影響讀取速度。

每個數(shù)據(jù)文件(.data 結(jié)尾)都有一個對應(yīng)的索引文件(.head 結(jié)尾),該索引文件對每張表都有一數(shù)據(jù)塊的摘要信息,記錄了每個數(shù)據(jù)塊在數(shù)據(jù)文件中的偏移量,數(shù)據(jù)的起止時間等信息,以幫助系統(tǒng)迅速定位需要查找的數(shù)據(jù)。每個數(shù)據(jù)文件還有一對應(yīng)的 last 文件(.last 結(jié)尾),該文件是為防止落盤時數(shù)據(jù)塊碎片化而設(shè)計的。如果一張表落盤的記錄條數(shù)沒有達到系統(tǒng)配置參數(shù) minRows(每塊最小記錄條數(shù)),將被先存儲到 last 文件,等下次落盤時,新落盤的記錄將與 last 文件的記錄進行合并,再寫入數(shù)據(jù)文件。

數(shù)據(jù)寫入磁盤時,根據(jù)系統(tǒng)配置參數(shù) comp 決定是否壓縮數(shù)據(jù)。TDengine 提供了三種壓縮選項:無壓縮、一階段壓縮和兩階段壓縮,分別對應(yīng) comp 值為 0、1 和 2 的情況。一階段壓縮根據(jù)數(shù)據(jù)的類型進行了相應(yīng)的壓縮,壓縮算法包括 delta-delta 編碼、simple 8B 方法、zig-zag 編碼、LZ4 等算法。二階段壓縮在一階段壓縮的基礎(chǔ)上又用通用壓縮算法進行了壓縮,壓縮率更高。

多級存儲

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

在默認配置下,TDengine 會將所有數(shù)據(jù)保存在 /var/lib/taos 目錄下,而且每個 vnode 的數(shù)據(jù)文件保存在該目錄下的不同目錄。為擴大存儲空間,盡量減少文件讀取的瓶頸,提高數(shù)據(jù)吞吐率 TDengine 可通過配置系統(tǒng)參數(shù) dataDir 讓多個掛載的硬盤被系統(tǒng)同時使用。

除此之外,TDengine 也提供了數(shù)據(jù)分級存儲的功能,將不同時間段的數(shù)據(jù)存儲在掛載的不同介質(zhì)上的目錄里,從而實現(xiàn)不同“熱度”的數(shù)據(jù)存儲在不同的存儲介質(zhì)上,充分利用存儲,節(jié)約成本。比如,最新采集的數(shù)據(jù)需要經(jīng)常訪問,對硬盤的讀取性能要求高,那么用戶可以配置將這些數(shù)據(jù)存儲在 SSD 盤上。超過一定期限的數(shù)據(jù),查詢需求量沒有那么高,那么可以存儲在相對便宜的 HDD 盤上。

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

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

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

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

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. 禁止手動移除使用中的掛載盤,掛載盤目前不支持非本地的網(wǎng)絡(luò)盤。
  3. 多級存儲目前不支持刪除已經(jīng)掛載的硬盤的功能。

數(shù)據(jù)查詢

TDengine 提供了多種多樣針對表和超級表的查詢處理功能,除了常規(guī)的聚合查詢之外,還提供針對時序數(shù)據(jù)的窗口查詢、統(tǒng)計聚合等功能。TDengine 的查詢處理需要客戶端、vnode、mnode 節(jié)點協(xié)同完成。

單表查詢

SQL 語句的解析和校驗工作在客戶端完成。解析 SQL 語句并生成抽象語法樹(Abstract Syntax Tree, AST),然后對其進行校驗和檢查。以及向管理節(jié)點(mnode)請求查詢中指定表的元數(shù)據(jù)信息(table metadata)。

根據(jù)元數(shù)據(jù)信息中的 End Point 信息,將查詢請求序列化后發(fā)送到該表所在的數(shù)據(jù)節(jié)點(dnode)。dnode 接收到查詢請求后,識別出該查詢請求指向的虛擬節(jié)點(vnode),將消息轉(zhuǎn)發(fā)到 vnode 的查詢執(zhí)行隊列。vnode 的查詢執(zhí)行線程建立基礎(chǔ)的查詢執(zhí)行環(huán)境,并立即返回該查詢請求,同時開始執(zhí)行該查詢。

客戶端在獲取查詢結(jié)果的時候,dnode 的查詢執(zhí)行隊列中的工作線程會等待 vnode 執(zhí)行線程執(zhí)行完成,才能將查詢結(jié)果返回到請求的客戶端。

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

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

在 TDengine 中引入關(guān)鍵詞 interval 來進行時間軸上固定長度時間窗口的切分,并按照時間窗口對數(shù)據(jù)進行聚合,對窗口范圍內(nèi)的數(shù)據(jù)按需進行聚合。例如:

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

針對 d1001 設(shè)備采集的數(shù)據(jù),按照1小時的時間窗口返回每小時存儲的記錄數(shù)量。

在需要連續(xù)獲得查詢結(jié)果的應(yīng)用場景下,如果給定的時間區(qū)間存在數(shù)據(jù)缺失,會導(dǎo)致該區(qū)間數(shù)據(jù)結(jié)果也丟失。TDengine 提供策略針對時間軸聚合計算的結(jié)果進行插值,通過使用關(guān)鍵詞 fill 就能夠?qū)r間軸聚合結(jié)果進行插值。例如:

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 設(shè)備采集數(shù)據(jù)統(tǒng)計每小時記錄數(shù),如果某一個小時不存在數(shù)據(jù),則返回之前一個小時的統(tǒng)計數(shù)據(jù)。TDengine 提供前向插值(prev)、線性插值(linear)、NULL值填充(NULL)、特定值填充(value)。

多表聚合查詢

TDengine 對每個數(shù)據(jù)采集點單獨建表,但在實際應(yīng)用中經(jīng)常需要對不同的采集點數(shù)據(jù)進行聚合。為高效的進行聚合操作,TDengine 引入超級表(STable)的概念。超級表用來代表一特定類型的數(shù)據(jù)采集點,它是包含多張表的表集合,集合里每張表的模式(schema)完全一致,但每張表都帶有自己的靜態(tài)標簽,標簽可以有多個,可以隨時增加、刪除和修改。應(yīng)用可通過指定標簽的過濾條件,對一個 STable 下的全部或部分表進行聚合或統(tǒng)計操作,這樣大大簡化應(yīng)用的開發(fā)。其具體流程如下圖所示:

多表聚合查詢原理圖

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

由于 TDengine 在 vnode 內(nèi)將標簽數(shù)據(jù)與時序數(shù)據(jù)分離存儲,通過在內(nèi)存里過濾標簽數(shù)據(jù),先找到需要參與聚合操作的表的集合,將需要掃描的數(shù)據(jù)集大幅減少,大幅提升聚合計算速度。同時,由于數(shù)據(jù)分布在多個 vnode/dnode,聚合計算操作在多個 vnode 里并發(fā)進行,又進一步提升了聚合的速度。 對普通表的聚合函數(shù)以及絕大部分操作都適用于超級表,語法完全一樣,細節(jié)請看 TAOS SQL。

預(yù)計算

為有效提升查詢處理的性能,針對物聯(lián)網(wǎng)數(shù)據(jù)的不可更改的特點,在數(shù)據(jù)塊頭部記錄該數(shù)據(jù)塊中存儲數(shù)據(jù)的統(tǒng)計信息:包括最大值、最小值、和。我們稱之為預(yù)計算單元。如果查詢處理涉及整個數(shù)據(jù)塊的全部數(shù)據(jù),直接使用預(yù)計算結(jié)果,完全不需要讀取數(shù)據(jù)塊的內(nèi)容。由于預(yù)計算數(shù)據(jù)量遠小于磁盤上存儲的數(shù)據(jù)塊數(shù)據(jù)的大小,對于磁盤 I/O 為瓶頸的查詢處理,使用預(yù)計算結(jié)果可以極大地減小讀取 I/O 壓力,加速查詢處理的流程。預(yù)計算機制與 Postgre SQL 的索引 BRIN(block range index)有異曲同工之妙。