聊聊時(shí)序數(shù)據(jù)庫(kù)
前陣子有朋友留言希望我寫篇關(guān)于時(shí)序數(shù)據(jù)庫(kù)的文章,以前我討論的數(shù)據(jù)庫(kù)大多數(shù)是RDBMS,其他數(shù)據(jù)庫(kù)討論的不多。說(shuō)實(shí)在的對(duì)于時(shí)序數(shù)據(jù)庫(kù),我也只是一個(gè)小學(xué)生,我的客戶使用時(shí)序數(shù)據(jù)庫(kù)在一個(gè)應(yīng)用系統(tǒng)中只是一部分很小的功能,大部分的應(yīng)用系統(tǒng)的主要數(shù)據(jù)還是使用關(guān)系型數(shù)據(jù)庫(kù)。
隨著工業(yè)互聯(lián)網(wǎng)的發(fā)展,以及物聯(lián)網(wǎng)技術(shù)與應(yīng)用的發(fā)展,時(shí)序數(shù)據(jù)庫(kù)變得越來(lái)越熱了。時(shí)序數(shù)據(jù)庫(kù)是一種特殊的數(shù)據(jù)庫(kù)管理系統(tǒng),針對(duì)時(shí)間序列數(shù)據(jù)的處理進(jìn)行了優(yōu)化,每條記錄都有時(shí)間戳。時(shí)序數(shù)據(jù)可能由物聯(lián)網(wǎng)中的傳感器、智能儀表或 RFID 產(chǎn)生,也可以由電網(wǎng)運(yùn)行的各個(gè)采集點(diǎn)中產(chǎn)生,也可以從股票交易記錄中產(chǎn)生。
時(shí)序數(shù)據(jù)的處理與關(guān)系型數(shù)據(jù)庫(kù)的處理事不同的,時(shí)序數(shù)據(jù)庫(kù)旨在有效地收集、存儲(chǔ)和查詢高頻產(chǎn)生的各種時(shí)間序列數(shù)據(jù)。并在數(shù)據(jù)庫(kù)的入庫(kù)、批量查詢、時(shí)序數(shù)據(jù)分析和過(guò)期數(shù)據(jù)自動(dòng)處理等方面有著獨(dú)特的方式。盡管可以使用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)或者鍵值數(shù)據(jù)庫(kù)來(lái)管理時(shí)序數(shù)據(jù)。其特點(diǎn)是大批量的寫入帶有時(shí)間戳的數(shù)據(jù),可能高達(dá)每秒幾百萬(wàn)甚至幾千萬(wàn)個(gè)。同時(shí)數(shù)據(jù)被一次寫入后不再修改,會(huì)被多次讀取使用。這些數(shù)據(jù)要么被用于實(shí)時(shí)分析,要么被用于事后研究。一般應(yīng)用軟件會(huì)按照某種規(guī)則按照時(shí)間區(qū)間來(lái)裝載一批數(shù)據(jù),或者通過(guò)內(nèi)建的統(tǒng)計(jì)函數(shù)去分析這些數(shù)據(jù)。這種應(yīng)用往往不太關(guān)注單點(diǎn)的數(shù)據(jù)或者幾個(gè)數(shù)據(jù)之間的關(guān)系。
因?yàn)橛幸徊糠謹(jǐn)?shù)據(jù)量并不是很大的時(shí)序數(shù)據(jù)庫(kù)應(yīng)用可以采用關(guān)系型數(shù)據(jù)庫(kù)、HBASE、REDIS這樣的KV數(shù)據(jù)庫(kù)來(lái)存儲(chǔ),因此在日常應(yīng)用中純時(shí)序數(shù)據(jù)庫(kù)使用的相對(duì)較少。因此時(shí)序數(shù)據(jù)庫(kù)這些年發(fā)展的不溫不火。從DB-ENGINES上看,純粹的時(shí)序數(shù)據(jù)庫(kù)的流行度得分并不高。
以第一模式為時(shí)序數(shù)據(jù)庫(kù)類型的數(shù)據(jù)庫(kù)排名看,排名最高的InfluxDB也僅僅29.15分,在數(shù)據(jù)庫(kù)流行度排名中十分靠后。如果我們把主要數(shù)據(jù)庫(kù)模式是其他類型,第二模式帶有時(shí)序數(shù)據(jù)庫(kù)模式的數(shù)據(jù)庫(kù)加上,看到的是一個(gè)完全不同的情況。
在這里我們看到了一些大佬的身影,特別是現(xiàn)在大火的MongDB,作為文檔數(shù)據(jù)庫(kù),MongoDB實(shí)際上是一種多模數(shù)據(jù)庫(kù),也支持時(shí)序數(shù)據(jù)。在國(guó)內(nèi)MongoDB僅僅被作為文檔數(shù)據(jù)庫(kù)使用,僅僅存儲(chǔ)一些目錄與日志信息,不過(guò)MongoDB是一個(gè)十分全能的數(shù)據(jù)庫(kù)產(chǎn)品,支持強(qiáng)一致性交易,甚至在時(shí)序數(shù)據(jù)庫(kù)模式上也十分強(qiáng)大。西門子、博世等世界五百?gòu)?qiáng)企業(yè)用MongoDB來(lái)處理時(shí)序數(shù)據(jù)。在目前XC替代方面,實(shí)際上MongoDB是十分難以替代的,特別是你真正用了MongDB的事務(wù)、時(shí)序特性等,沒有第二個(gè)數(shù)據(jù)庫(kù)產(chǎn)品擁有MongoDB如此強(qiáng)大的功能。而MongoDB從商業(yè)利益上考慮將開源協(xié)議轉(zhuǎn)為SSPL后,開始收割云服務(wù)廠商,而這種接近于商用協(xié)議的開源協(xié)議極容易受到美國(guó)政府出口管制措施的影響,因此對(duì)于有XC要求的企業(yè)來(lái)說(shuō),還是要十分小心的。
令人意外的事Redis這種我們經(jīng)常用來(lái)做緩沖的,十分簡(jiǎn)單的內(nèi)存KV數(shù)據(jù)庫(kù),也是多模的,也支持時(shí)序數(shù)據(jù)。Redis支持SortedSets數(shù)據(jù)結(jié)構(gòu),支持按權(quán)重存儲(chǔ)數(shù)據(jù)并支持按照權(quán)重的范圍查詢。如果把時(shí)間戳作為權(quán)重值,key存儲(chǔ)具體的度量維度,那么Redis就可以支持時(shí)序數(shù)據(jù)了。不過(guò)這種模式過(guò)于簡(jiǎn)單粗暴,十分消耗內(nèi)存,而且并發(fā)寫入性能也不好,只適合最為簡(jiǎn)單的模式。從Redis 5.0開始,Redis開始支持消息隊(duì)列Stream,流式數(shù)據(jù)也是時(shí)序數(shù)據(jù)處理中的一種常見場(chǎng)景。而真正讓Redis具有真正的流式數(shù)據(jù)庫(kù)能力的是Redis TimeSeries擴(kuò)展模塊的引入。這是
在這個(gè)列表里我們還看到了最近比較火的ClickHose。Clickhouse是俄羅斯yandex公司于2016年開源的一個(gè)列式數(shù)據(jù)庫(kù)管理系統(tǒng),近些年像一匹黑馬一樣迅速在具有時(shí)序處理需求的OLAP場(chǎng)景中收割用戶。其向量化引擎SIMD讓一些大數(shù)據(jù)量的簡(jiǎn)單分析查詢性能得到了極大的釋放。只不過(guò)ClickHose簡(jiǎn)單粗暴的向量引擎限制了應(yīng)用的并發(fā),不過(guò)在OLAP場(chǎng)景中,高并發(fā)并不總是剛需。
大多數(shù)時(shí)序數(shù)據(jù)庫(kù)的應(yīng)用場(chǎng)景可以將時(shí)序數(shù)據(jù)庫(kù)獨(dú)立開來(lái)存儲(chǔ)與訪問(wèn),而應(yīng)用中的較為復(fù)雜的業(yè)務(wù)數(shù)據(jù)可以放在關(guān)系型數(shù)據(jù)庫(kù)里。而時(shí)序數(shù)據(jù)的讀寫場(chǎng)景相對(duì)簡(jiǎn)單,因此時(shí)序數(shù)據(jù)庫(kù)在數(shù)據(jù)庫(kù)領(lǐng)域的熱度較低。
有些關(guān)系型數(shù)據(jù)庫(kù)用戶開始的時(shí)候都把時(shí)序數(shù)據(jù)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)里,不過(guò)因?yàn)闀r(shí)序數(shù)據(jù)的數(shù)據(jù)量太大了。會(huì)導(dǎo)致關(guān)系型數(shù)據(jù)庫(kù)的容量變得超大,我以前做過(guò)一個(gè)優(yōu)化項(xiàng)目,業(yè)務(wù)數(shù)據(jù)庫(kù)的庫(kù)容高達(dá)上百TB,而實(shí)際上里面的關(guān)系型的業(yè)務(wù)數(shù)據(jù)只有幾百GB,大多數(shù)都是寫入后只讀的時(shí)序數(shù)據(jù)。后來(lái)我建議他們吧時(shí)序數(shù)據(jù)獨(dú)立出去了,這樣數(shù)據(jù)庫(kù)備份,運(yùn)維就簡(jiǎn)單多了。
而把超大規(guī)模的時(shí)序數(shù)據(jù)寫入關(guān)系型數(shù)據(jù)庫(kù),很可能就會(huì)到達(dá)關(guān)系型數(shù)據(jù)庫(kù)的天花板,讓數(shù)據(jù)庫(kù)的性能無(wú)法跟上。如果把這類數(shù)據(jù)存儲(chǔ)到純粹的時(shí)序數(shù)據(jù)庫(kù)里,那么就很容易利用其分布式特性很好的橫向擴(kuò)展了。時(shí)序數(shù)據(jù)庫(kù)存儲(chǔ)這些數(shù)據(jù)的時(shí)候,會(huì)占用更小的空間,也很容易實(shí)現(xiàn)自動(dòng)的數(shù)據(jù)壓縮。另外利用專用的API訪問(wèn)時(shí)間,對(duì)數(shù)據(jù)做復(fù)雜的匯總統(tǒng)計(jì),也比SQL接口要快捷的多。因此很多企業(yè)都陸續(xù)將時(shí)序數(shù)據(jù)從傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)中分離出來(lái),存儲(chǔ)到專業(yè)的時(shí)序數(shù)據(jù)庫(kù)中。
不過(guò)還有另外一種思路,那就是在關(guān)系型數(shù)據(jù)庫(kù)中增加時(shí)序數(shù)據(jù)庫(kù)的能力。最為典型的就是TimeScaleDB。當(dāng)時(shí)序數(shù)據(jù)的量還不算太大的時(shí)候,有些用戶選擇了將時(shí)序數(shù)據(jù)存儲(chǔ)到關(guān)系型數(shù)據(jù)庫(kù)中。在PostgreSQL數(shù)據(jù)庫(kù)中安裝TimeScaleDB插件,創(chuàng)建時(shí)序表來(lái)存儲(chǔ)時(shí)序數(shù)據(jù)。同事利用PG的SQL引擎來(lái)訪問(wèn)和處理這些時(shí)序數(shù)據(jù)。利用TimeScaleDB的歷史數(shù)據(jù)自動(dòng)壓縮功能壓縮歷史數(shù)據(jù),可以大大減少海量歷史數(shù)據(jù)的存儲(chǔ)量。我們的D-SMART中需要采集大量的數(shù)據(jù)庫(kù)的監(jiān)控?cái)?shù)據(jù),大概每2分鐘采集一次,每次有上千個(gè)實(shí)例,每個(gè)實(shí)例有數(shù)百條記錄。這樣的話,一個(gè)納管了2000個(gè)數(shù)據(jù)庫(kù)的D-SMART,每隔兩分鐘,就會(huì)有100萬(wàn)條數(shù)據(jù)被寫入TimeScaleDB,并且這些數(shù)據(jù)還需要按照時(shí)間區(qū)間,通過(guò)SQL查詢出來(lái),進(jìn)行分析處理。從這些年的使用來(lái)看,TimeScaleDB是可以輕松應(yīng)對(duì)這樣的場(chǎng)景的,每個(gè)SQL查詢也都是幾十毫秒就可以完成。我們最初是使用PG的普通表存儲(chǔ)這些監(jiān)控?cái)?shù)據(jù)的,換成TimeScaleDB后,寫入性能與查詢性能都有了多倍的提升。最令我們喜歡的是歷史數(shù)據(jù)的自動(dòng)壓縮功能,作為運(yùn)維自動(dòng)化系統(tǒng),7天前的監(jiān)控?cái)?shù)據(jù)被訪問(wèn)的比例很低,因此我們?cè)O(shè)置了7天數(shù)據(jù)自動(dòng)壓縮,大大節(jié)約了存儲(chǔ)資源。
使用TimeScaleDB最大的好處是保留了我們團(tuán)隊(duì)在SQL上的所有研發(fā)經(jīng)驗(yàn),只要不亂寫SQL,大部分SQL不需要特殊的優(yōu)化改寫,就可以達(dá)到性能要求。實(shí)現(xiàn)這種開發(fā)自由來(lái)自于TimeScaleDB優(yōu)秀的設(shè)計(jì),因?yàn)闀r(shí)間問(wèn)題,我們?cè)谶@里就展開討論了。如果是千萬(wàn)到數(shù)億級(jí)別的時(shí)序數(shù)據(jù)處理,使用TimeScaleDB是沒有任何壓力的。
國(guó)產(chǎn)的時(shí)序數(shù)據(jù)庫(kù)產(chǎn)品也很多,在墨天輪上目前有32種國(guó)產(chǎn)時(shí)序數(shù)據(jù)庫(kù),已經(jīng)和DB-ENGINES上35種純時(shí)序數(shù)據(jù)庫(kù)的列表差不多長(zhǎng)了。其中排名靠前的濤思數(shù)據(jù)的TDengine和智叟科技的DolphinDB。在DB-ENGINES的時(shí)序數(shù)據(jù)庫(kù)排行中,這兩種時(shí)序數(shù)據(jù)庫(kù)也比較靠前。也有一些國(guó)產(chǎn)時(shí)序數(shù)據(jù)庫(kù)基于openTSDB,或者與之兼容。
時(shí)序數(shù)據(jù)庫(kù)與時(shí)序應(yīng)用的發(fā)展呈現(xiàn)出三種模式,大家也都在爭(zhēng)論哪種模式更好。
第一種模式是放棄關(guān)系型數(shù)據(jù)庫(kù),轉(zhuǎn)向時(shí)序數(shù)據(jù)庫(kù)或者用帶有時(shí)序數(shù)據(jù)庫(kù)模式的多模數(shù)據(jù)庫(kù)替代關(guān)系型數(shù)據(jù)庫(kù)。利用原生分布式架構(gòu),帶有向量處理能力的數(shù)據(jù)庫(kù)引擎來(lái)支撐特別大數(shù)據(jù)量寫入,大數(shù)據(jù)量輸出需求的場(chǎng)景。這些人認(rèn)為NOSQL才是時(shí)序數(shù)據(jù)處理的最終解決方案。
第二種模式正好相反,他們從NOSQL的時(shí)序數(shù)據(jù)庫(kù)轉(zhuǎn)向了具有時(shí)序數(shù)據(jù)處理能力的關(guān)系型數(shù)據(jù)庫(kù),充分利用SQL的能力來(lái)解決應(yīng)用的問(wèn)題。最典型的就是我今天介紹的D-SMART里使用的TimeScaleDB。對(duì)于更大數(shù)據(jù)量的需求,可以使用CrateDB、TDengine這樣的分布式數(shù)據(jù)庫(kù)。
第三種模式是使用HBASE這樣的KV數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)時(shí)序數(shù)據(jù),而不專門使用時(shí)序數(shù)據(jù)庫(kù)。對(duì)于僅僅把海量時(shí)序數(shù)據(jù)找個(gè)地方存起來(lái),滿足大并發(fā)寫入,大吞吐量輸出的場(chǎng)景要求就行了,大量的數(shù)據(jù)處理都是應(yīng)用程序自己來(lái)干,那么這樣的用法也沒啥問(wèn)題。
實(shí)際上也無(wú)需爭(zhēng)論,因?yàn)椴煌膽?yīng)用場(chǎng)景就會(huì)選擇不同的模式。到底你選擇什么樣的時(shí)序數(shù)據(jù)庫(kù)方案,往往取決于下面幾個(gè)因素:1)你的時(shí)序數(shù)據(jù)的量級(jí)是什么樣的,每秒幾萬(wàn),幾十萬(wàn),還是幾百萬(wàn),幾千萬(wàn);2)你的時(shí)序數(shù)據(jù)如何被使用,每次讀取的批次是多少;3)你需要數(shù)據(jù)庫(kù)的內(nèi)置功能來(lái)處理和分析時(shí)序數(shù)據(jù),還是有自己的數(shù)據(jù)分析應(yīng)用模塊;4)你如何處理過(guò)期的數(shù)據(jù);5)你的歷史數(shù)據(jù)的訪問(wèn)模式;6)你的查詢并發(fā)QPS是多少;……。
我想你把這幾個(gè)問(wèn)題考慮清楚了,再根據(jù)目前主流的時(shí)序數(shù)據(jù)庫(kù)或者帶有時(shí)序功能的多模數(shù)據(jù)庫(kù)的特征去找尋,那么就不難做出相對(duì)靠譜的選擇了。