在(zai)(zai)去年 8 月份發布的(de)(de) 3.1.0.0 版本中,TDengine 進行了一(yi)系列重要(yao)的(de)(de)企業級功能更(geng)新,其中包括(kuo)對(dui)多(duo)表低頻場景寫入性能的(de)(de)大幅優化(hua)(hua)。這一(yi)優化(hua)(hua)工作(zuo)為(wei)有(you)此需求(qiu)的(de)(de)用(yong)戶(hu)提供了更(geng)大的(de)(de)便捷性和(he)易用(yong)性。在(zai)(zai)本文中,TDengine 的(de)(de)資深研發將對(dui)此次優化(hua)(hua)工作(zuo)進行深入分析介紹,并從實踐層(ceng)面剖析本次功能升級的(de)(de)具體作(zuo)用(yong)。
三種時序場景分析
以 TDengine 的客(ke)戶群體作為(wei)分(fen)析樣本,我們(men)發現,企業的時序(xu)場(chang)景(jing)大概可以分(fen)為(wei)以下(xia)三種類(lei)型:
- 少表高頻
- 表的數量小,一般少于 100 萬張表。
- 數據采集頻率高,多為秒級甚至毫秒級。
- 在存儲引擎看來,大量寫入的數據中,同一張表的數據被多次寫入,且時間戳遞增,或有極少數的亂序。
- 當內存中的數據積攢到一定的量需要落盤時,同一張表的數據大量存在,可以生成多個數據塊。
- 多表低頻(High Cardinality)
- 表的數量大,一般多于 100 萬張表,達到千萬、億級別。
- 表的采集頻率很低,多為分鐘級采集,也有小時級和天級的采集頻率。
- 在存儲引擎看來,大量寫入的數據中,同一張表只有幾條甚至一條數據的寫入。
- 數據落盤時,每張表只有一條或幾條記錄,無法生成一個完整的數據塊。
- 無限熱點表
- 每張表只在一段時間內數據頻繁更新寫入,成為寫入熱點,其后很少或根本不再有數據的寫入。
- 在不同的時間段內,寫入熱點表一直改變,且持續創建新的表。
- 如果以 TDengine 的數據模型建表,表數將達到無限。
- 在存儲看來,該場景兼具多表低頻和少表高頻的特點。
- 在一段時間內,某些表寫入數據非常多。落盤時,同一張表的數據可能會產生多個數據塊,表現出高頻的特性。而大部分表不寫入數據。
- 隨著時間的推移,表的數量會非常龐大,表現出多表的特性。

對于少(shao)表低(di)(di)頻的(de)場(chang)景來說,由于數據量不大(da),用任何(he)方案都可以解決。而多表高頻的(de)場(chang)景,在有限的(de)硬(ying)件資(zi)源下(xia)會轉(zhuan)變為多表低(di)(di)頻場(chang)景,在無(wu)限的(de)硬(ying)件資(zi)源下(xia),則會轉(zhuan)變為少(shao)表高頻場(chang)景。
在(zai) TDengine 的用(yong)戶(hu)群體中,部分多(duo)表(biao)低頻(pin)(pin)的用(yong)戶(hu)也可以(yi)通(tong)過增(zeng)加節(jie)點,即增(zeng)加 vnode 個(ge)數,使用(yong)更多(duo)的硬(ying)件(jian)資源(yuan)將多(duo)表(biao)低頻(pin)(pin)場(chang)景(jing)(jing)轉化為了少(shao)表(biao)高(gao)頻(pin)(pin)場(chang)景(jing)(jing),從而較為高(gao)效地利(li)用(yong) TDengine 在(zai)少(shao)表(biao)高(gao)頻(pin)(pin)場(chang)景(jing)(jing)下(xia)的高(gao)性(xing)能,但增(zeng)加硬(ying)件(jian)資源(yuan)本身(shen)和 TDengine 的初衷(zhong)(為用(yong)戶(hu)節(jie)省(sheng)硬(ying)件(jian)資源(yuan))相違背。以(yi)北京燃氣舉例,在(zai) 300萬+ 燃氣表(biao)、每個(ge)燃氣表(biao)每天采集一條記錄的場(chang)景(jing)(jing)下(xia),用(yong) TDengine 3.0 處理,通(tong)過增(zeng)大(da) vnode 個(ge)數將之轉化為少(shao)表(biao)高(gao)頻(pin)(pin)的場(chang)景(jing)(jing)后,相比(bi)用(yong)戶(hu)以(yi)前(qian)用(yong) Oracle 時成本并未節(jie)省(sheng)多(duo)少(shao)。
對于無限熱點表(biao)(biao)場(chang)景來說(shuo),如果用 TDengine 來處理該(gai)(gai)場(chang)景,隨著時間(jian)的(de)(de)推移(yi),表(biao)(biao)的(de)(de)數量(liang)會(hui)越(yue)來越(yue)多,效率會(hui)越(yue)來越(yue)低(di),成本(ben)會(hui)越(yue)來越(yue)高(gao)直至(zhi)不可用。不過(guo),TDengine 3.0 提供了表(biao)(biao)的(de)(de) TTL(Time-To-Live)功能,用戶(hu)可以通過(guo)該(gai)(gai)功能設(she)置過(guo)期(qi)表(biao)(biao)自動刪(shan)除,從而(er)控制表(biao)(biao)的(de)(de)數目不至(zhi)于達(da)到無限。但該(gai)(gai)場(chang)景最終也退化成了多表(biao)(biao)高(gao)頻場(chang)景。
有人說這三種(zhong)場(chang)景可以(yi)(yi)統(tong)一為一種(zhong)模型(xing)處理(li)(li),即 InfluxDB 的(de)(de)(de)(de)模型(xing):對一個時間線指定(ding) tag,數(shu)(shu)據(ju)(ju)為采集數(shu)(shu)據(ju)(ju)。鑒于(yu) InfluxDB 以(yi)(yi)該數(shu)(shu)據(ju)(ju)模型(xing)設計(ji)的(de)(de)(de)(de)存儲模型(xing)的(de)(de)(de)(de)表(biao)現,個人認(ren)為,InfluxDB 的(de)(de)(de)(de)數(shu)(shu)據(ju)(ju)模型(xing)除了能幫助大家很好地理(li)(li)解(jie)時序數(shu)(shu)據(ju)(ju)這個優點(dian)之外,對于(yu)解(jie)決上述多表(biao)低頻和無(wu)限熱點(dian)表(biao)場(chang)景沒(mei)有任何(he)實際價值。且 InfluxDB 本身對于(yu) tag 取(qu)值范圍大的(de)(de)(de)(de)場(chang)景(High Cardinality)處理(li)(li)非常差,以(yi)(yi)致于(yu)。
從以上(shang)角度出發,隨著 TDengine 3.0 版本的逐步更(geng)新,我們開始針對多表(biao)低頻(pin)場景寫(xie)入性能開展優(you)化工作。
TDengine 存儲引擎設計概述
從根本上(shang)來(lai)說,TDengine 的設計和實現(xian)來(lai)自(zi)于對時序(xu)數據(ju)十(shi)大特(te)點的總結和一個數據(ju)模型(xing)的確定。
- 時序數據十大特點:

- TDengine 數據模型:一個采集點一張表
TDengine 采用一個采集點一張表的數據模型,主要是要利用時序這一特點。

TDengine 存儲(chu)引擎(qing)整體(ti)采(cai)用了(le) LSM 的存儲(chu)架構(gou)。其結構(gou)如下(xia)圖所示:

TDengine 的文件系統如下:

文件組的結構如下:

存儲引擎優化工作的具體展開
明確優化要解決的問題
- 解決在多表場景下寫放大問題
在少表高頻的場景下,TDengine 充分利用了有序這個特點,在該場景下的寫入性能相比同類型數據庫高出一個甚至幾個數量級,達到最優 O(N) 的時間復雜度。在存儲格式上,我們假設落盤時一張表的數據大量存在,從而設計了硬盤上一個數據塊只包含一張表的數據這樣一種結構。

但是在多表場景下,從存儲引擎的角度來講,上述的很多特性會發生改變。由于存儲引擎可以利用的內存資源有限,在內存可緩存的數據里,屬于同一張表的數據只有很少的幾條,甚至一條。在這種情況下,有序這個特點(dian)幾(ji)乎無用,我們(men)針對(dui)有序做的優化在(zai)多表場(chang)景下趨于無效,甚至會導致寫放大(da)問題。

在存儲引擎看來,多表低頻場景下的數據寫入是純亂序的。從理論(lun)上來(lai)講,該場景下數(shu)據寫入的最優處(chu)理復雜度為 O(NlogN)。
- 在多表低頻場景下,stt_trigger 配置大以后寫入周期性出現卡頓的問題
TDengine 后臺(tai)有一個(ge)專門用來落盤(pan)(pan)的(de)線(xian)程池,負責將 imem 中(zhong)的(de)數(shu)據持久(jiu)化到(dao)硬盤(pan)(pan)文(wen)(wen)件上。這個(ge)文(wen)(wen)件可能(neng)(neng)是 stt 文(wen)(wen)件,也有可能(neng)(neng)是 data 文(wen)(wen)件中(zhong)。如果生成了 stt 文(wen)(wen)件,并(bing)且(qie) stt 個(ge)數(shu)達到(dao)了 stt_trigger,commit 線(xian)程則會(hui)將 imem 和 多個(ge) stt 文(wen)(wen)件中(zhong)的(de)數(shu)據合并(bing),寫(xie)(xie)入(ru) data 文(wen)(wen)件或者生成新(xin)的(de) stt 文(wen)(wen)件。這個(ge)合并(bing)可能(neng)(neng)涉及非常多的(de)數(shu)據的(de)讀(du)和寫(xie)(xie),從而(er)使得落盤(pan)(pan)時間非常久(jiu),久(jiu)到(dao)新(xin)的(de) mem 被寫(xie)(xie)滿,會(hui)阻塞寫(xie)(xie)入(ru)進程一段時間,直至合并(bing)完(wan)成。
- compact、retention 功能阻塞寫入的問題
由于 compact、retention、commit 均需對文件進(jin)行操(cao)作(zuo),且這些(xie)操(cao)作(zuo)可(ke)能(neng)動相(xiang)同的(de)(de)文件,因此這三(san)個操(cao)作(zuo)只能(neng)串行操(cao)做,從而導致 compact 或 retention 阻(zu)塞(sai) commit,出現(xian)阻(zu)塞(sai)寫入(ru)進(jin)程的(de)(de)問題。
存儲數據調整
- stt 文件中一個數據塊中可以包含多張表的數據(3.0 發布時已完成)
從上(shang)面的分析可以看到,一(yi)個(ge)數(shu)(shu)(shu)(shu)據(ju)(ju)塊(kuai)只有(you)一(yi)張表的數(shu)(shu)(shu)(shu)據(ju)(ju),在(zai)(zai)多(duo)表低(di)(di)頻場景下,會導致數(shu)(shu)(shu)(shu)據(ju)(ju)寫放大嚴重,且不利于壓縮,讀取時(shi)效率也非常(chang)低(di)(di)。因此,在(zai)(zai)優化中,我們將(jiang) stt 中屬于同一(yi)個(ge)超級(ji)表的數(shu)(shu)(shu)(shu)據(ju)(ju)合并在(zai)(zai)一(yi)個(ge)數(shu)(shu)(shu)(shu)據(ju)(ju)塊(kuai)中,該數(shu)(shu)(shu)(shu)據(ju)(ju)塊(kuai)可能(neng)含有(you)多(duo)個(ge)表的數(shu)(shu)(shu)(shu)據(ju)(ju),這樣就使得 stt 文件中的數(shu)(shu)(shu)(shu)據(ju)(ju)塊(kuai)數(shu)(shu)(shu)(shu)量減少了至少 3 個(ge)數(shu)(shu)(shu)(shu)量級(ji)。
- stt 文件中添加統計信息
為了提升 TDengine 查詢(xun)引擎對于(yu) stt 的處理(li)效率,我們(men)在新的 stt 文件中(zhong)增加了每張表的統(tong)計(ji)信息。
- 刪除數據(Tombstone Data)分布到各個文件組
在老的(de)存儲中刪(shan)(shan)(shan)除文件(jian)(jian)是單獨存在的(de)。為(wei)了避(bi)免 commit 與其他操作處理同(tong)一個文件(jian)(jian),我(wo)們決(jue)定將刪(shan)(shan)(shan)除數據分布(bu)到不同(tong)的(de)文件(jian)(jian)組(zu)中,并增(zeng)加 tomb 文件(jian)(jian)。刪(shan)(shan)(shan)除數據可(ke)能存在于 tomb 文件(jian)(jian)中或(huo)者 stt 文件(jian)(jian)中。
LSM 實現完善
在新(xin)的(de)優化中,我們(men)補齊(qi)了 LSM 的(de)另一環,即后(hou)臺(tai)的(de) merge。后(hou)臺(tai)的(de) merge 線程(cheng)將多個 stt 文件(jian)合并到 data 文件(jian)中或者生成新(xin)的(de) stt 文件(jian)。

commit 只負責生成新的(de) stt 文件,不再(zai)負責向(xiang) data 中寫入(ru)。這樣(yang)就可以(yi)將 commit 操作的(de)文件和 compact、retetion 以(yi)及 merge 操作的(de)文件隔離開(kai),從而實現并(bing)行(xing)(xing)進行(xing)(xing),避免 commit 被(bei)阻塞而出現寫入(ru)阻塞的(de)情況(kuang)。

為(wei)(wei)了盡(jin)量減少多(duo)表低頻場景下數據(ju)被多(duo)次 merge,我們還為(wei)(wei) stt 文件引(yin)入了分(fen)層的(de)概念。

頭文件列存
頭文件列(lie)存的(de)優化動力來源于國家(jia)地震(zhen)局臺網中心(xin)的(de)用戶場景。該用戶的(de)場景屬于少表(biao)高頻,表(biao)的(de)數據(ju)(ju)量(liang)不(bu)大,但是(shi)采集頻率(lv)是(shi)毫秒(miao)級的(de),因(yin)此數據(ju)(ju)量(liang)非(fei)常大,一天就有 3000 億條記錄(lu)寫(xie)(xie)入(ru)。由于數據(ju)(ju)寫(xie)(xie)入(ru)量(liang)非(fei)常大,導致數據(ju)(ju)塊非(fei)常多,這也導致頭文件非(fei)常大。由于頭文件在(zai)每次落盤時都可能(neng)重寫(xie)(xie),就導致讀(du)寫(xie)(xie)放大都十分嚴重。
因此,在本(ben)次優化中,我們將頭(tou)文(wen)件改為列存,并對每一列配以壓縮,從而使得(de)頭(tou)文(wen)件縮小到原來(lai)的(de) 1/10。改造后的(de)頭(tou)文(wen)件格式如(ru)下:

優化結果反饋
此(ci)次優(you)化一(yi)方面是(shi)為了(le)提(ti)高多(duo)表(biao)低(di)頻寫(xie)入(ru)(ru)的性(xing)能(neng)(neng),另一(yi)方面是(shi)為了(le)解決各(ge)種問題。整體來講,本次優(you)化的結果(guo)是(shi):在少表(biao)高頻場景(jing)下,寫(xie)入(ru)(ru)性(xing)能(neng)(neng)不(bu)降;多(duo)表(biao)低(di)頻場景(jing)寫(xie)入(ru)(ru)性(xing)能(neng)(neng)提(ti)升,并且寫(xie)入(ru)(ru)速度穩(wen)定(ding)。此(ci)次優(you)化在用(yong)戶實踐角度也反(fan)饋出良好效果(guo)——在北(bei)京燃氣 300 萬智(zhi)能(neng)(neng)電表(biao)項目中,3 個(ge) vnode 即可(ke)滿(man)足(zu)寫(xie)入(ru)(ru)需(xu)求,且寫(xie)入(ru)(ru)速度穩(wen)定(ding);在河南智(zhi)能(neng)(neng)電表(biao)項目中,用(yong)一(yi)臺(tai)較好的機(ji)器,如(ru) 64 核 128GB 內存,就可(ke)以(yi)解決以(yi)前需(xu)要幾十臺(tai)機(ji)器才能(neng)(neng)滿(man)足(zu)的寫(xie)入(ru)(ru)、查(cha)詢需(xu)求。
同(tong)時(shi)(shi),這種優(you)化(hua)方(fang)式對于數(shu)(shu)據(ju)(ju)(ju)的(de)亂(luan)(luan)序(xu)(xu)(xu)更新(xin)也(ye)帶來了(le)顯著的(de)好處(chu)。在(zai)一些無法在(zai)落盤時(shi)(shi)進行排序(xu)(xu)(xu)或合并的(de)更新(xin)數(shu)(shu)據(ju)(ju)(ju)情況下,通(tong)過后臺的(de) merge 操作,為亂(luan)(luan)序(xu)(xu)(xu)數(shu)(shu)據(ju)(ju)(ju)提(ti)供(gong)了(le)額(e)外的(de)處(chu)理機會。這樣,亂(luan)(luan)序(xu)(xu)(xu)數(shu)(shu)據(ju)(ju)(ju)可以被重(zhong)新(xin)排序(xu)(xu)(xu),未合并的(de)更新(xin)數(shu)(shu)據(ju)(ju)(ju)也(ye)可以得(de)到(dao)更新(xin)。這種優(you)化(hua)機制有效地提(ti)高了(le)數(shu)(shu)據(ju)(ju)(ju)的(de)整體處(chu)理效率和準(zhun)確(que)性。
結語
總而言之,通過此次優化,TDengine 進一步提升了在低頻場景下的寫入性能,使用戶能夠更高效地存儲和管理數據。這對于需要進行大規模數據處理的能源企業來說,將帶來更加卓越的數據處理能力和用戶體驗。如果你也有此場景需求,可以添加小T vx:tdengine 進行咨詢交流。


























