時序數據庫技術體系(一):時序數據存儲模型設計

時序數據庫技術體系中一個很是重要的技術點是時序數據模型設計,不一樣的時序系統有不一樣的設計模式,而不一樣的設計模式對時序數據的讀寫性能、數據壓縮效率等各個方面都有很是重要的影響。這篇文章筆者將會分別針對OpenTSDB、Druid、InfluxDB以及Beringei這四個時序系統中的時序數據模型設計進行介紹。算法

在詳細介紹時序數據模型以前,仍是有必要簡單回顧一下時序數據的幾個基本概念,以下圖所示:數據庫

 

 

上圖是一個典型的時序數據示意圖,由圖中能夠看出,時序數據由兩個維度座標來表示,橫座標表示時間軸,隨着時間的不斷流逝,數據也會源源不斷地吐出來;和橫座標不一樣,縱座標由兩種元素構成,分別是數據源和metric,數據源由一系列的標籤(tag,也稱爲維度)惟一表示,圖中數據源是一個廣告數據源,這個數據源由publisher、advertiser、gender以及country四個維度值惟一表示,metric表示待收集的數據源指標。一個數據源一般會採集不少指標(metric),上圖中廣告數據源就採集了impressions、clicks以及revenue這三種指標,分別表示廣告瀏覽量、廣告點擊率以及廣告收入。設計模式

看到這裏,相信你們對時序數據已經有了一個初步的瞭解,能夠簡單的歸納爲:一個時序數據點(point)由datasource(tags)+metric+timestamp這三部分惟一肯定。然而,這只是邏輯上的概念理解,那具體的時序數據庫究竟是如何將這樣一系列時序數據點進行存儲的呢?下文筆者針對OpenTSDB、Druid、InfluxDB以及Beringei四種系統進行介紹。緩存

 

OpenTSDB(HBase)時序數據存儲模型架構

 

OpenTSDB基於HBase存儲時序數據,在HBase層面設計RowKey規則爲:metric+timestamp+datasource(tags)。HBase是一個KV數據庫,一個時序數據(point)若是以KV的形式表示,那麼其中的V必然是point的具體數值,而K就天然而然是惟一肯定point數值的datasource+metric+timestamp。這種規律不只適用於HBase,還適用於其餘KV數據庫,好比Kudu。app

既然HBase中K是由datasource、metric以及timestamp三者構成,如今咱們能夠簡單認爲rowkey就爲這三者的組合,那問題來了:這三者的組合順序是怎麼樣的呢?性能

首先來看哪一個應該排在首位。由於HBase中一張表的數據組織方式是按照rowkey的字典序順序排列的,爲了將同一種指標的全部數據集中放在一塊兒,HBase將將metric放在了rowkey的最前面。假如將timestamp放在最前面,同一時刻的數據必然會寫入同一個數據分片,沒法起到散列的效果;而若是將datasource(即tags)放在最前面的話,這裏有個更大的問題,就是datasource自己由多個標籤組成,若是用戶指定其中部分標籤查找,並且不是前綴標籤的話,在HBase裏面將會變成大範圍的掃描過濾查詢,查詢效率很是之低。舉個上面的例子,若是將datasource放在最前面,那rowkey就能夠表示爲publisher=ultrarimfast.com&advertiser:google.com&gender:Male&country:USA_impressions_20110101000000,此時用戶想查找20110101000000這個時間點全部發布在USA的全部廣告的瀏覽量,即只根據country=USA這樣一個維度信息查找指定時間點的某個指標,並且這個維度不是前綴維度,就會掃描大量的記錄進行過濾。優化

肯定了metric放在最前面以後,再來看看接下來應該將datasource放在中間呢仍是應該將timestamp放在中間?將metric放在前面已經能夠解決請求均勻分佈(散列)的要求,所以HBase將timestamp放在中間,將datasource放在最後。試想,若是將datasource放在中間,也會遇到上文中說到的後綴維度查找的問題。ui

所以,OpenTSDB中rowkey的設計爲:metric+timestamp+datasource,好了,那HBase就能夠只設置一個columnfamily和一個column。那問題來了,OpenTSDB的這種設計有什麼問題?在瞭解設計問題以前須要簡單看看HBase在文件中存儲KV的方式,即一系列時序數據在文件、內存中的存儲方式,以下圖所示:google

上圖是HBase中一個存儲KeyValue(KV)數據的數據塊結構,一個數據塊由多個KeyValue數據組成,在咱們的事例中KeyValue就是一個時序數據點(point)。其中Value結構很簡單,就是一個數值。而Key就比較複雜了,由rowkey+columnfamily+column+timestamp+keytype組成,其中rowkey等於metric+timestamp+datasource。

問題一:存在不少無用的字段。一個KeyValue中只有rowkey是有用的,其餘字段諸如columnfamily、column、timestamp以及keytype從理論上來說都沒有任何實際意義,但在HBase的存儲體系裏都必須存在,於是耗費了很大的存儲成本。

問題二:數據源和採集指標冗餘。KeyValue中rowkey等於metric+timestamp+datasource,試想同一個數據源的同一個採集指標,隨着時間的流逝不斷吐出採集數據,這些數據理論上共用同一個數據源(datasource)和採集指標(metric),但在HBase的這套存儲體系下,共用是沒法體現的,所以存在大量的數據冗餘,主要是數據源冗餘以及採集指標冗餘。

問題三:沒法有效的壓縮。HBase提供了塊級別的壓縮算法-snappy、gzip等,這些通用壓縮算法並無針對時序數據進行設置,壓縮效率比較低。HBase一樣提供了一些編碼算法,好比FastDiff等等,能夠起到必定的壓縮效果,可是效果並不佳。效果不佳的主要緣由是HBase沒有數據類型的概念,沒有schema的概念,不能針對特定數據類型進行特定編碼,只能選擇通用的編碼,效果可想而知。

問題四:不能徹底保證多維查詢能力。HBase自己沒有schema,目前沒有實現倒排索引機制,全部查詢必須指定metric、timestamp以及完整的tags或者前綴tags進行查詢,對於後綴維度查詢也勉爲其難。

雖然說有這樣那樣的問題,可是OpenTSDB仍是針對存儲模型作了兩個方面的優化:

優化一:timestamp並非想象中細粒度到秒級或毫秒級,而是精確到小時級別,而後將小時中每一秒設置到列上。這樣一行就會有3600列,每一列表示一小時的一秒。這樣設置聽說能夠有效的取出一小時整的數據。

優化二:全部metrics以及全部標籤信息(tags)都使用了全局編碼將標籤值編碼成更短的bit,減小rowkey的存儲數據量。上文分析HBase這種存儲方式的弊端是說道會存在大量的數據源(tags)冗餘以及指標(metric)冗餘,有冗餘是吧,那我就搞個編碼,將string編碼成bit,盡最大努力減小冗餘。雖然說這樣的全局編碼能夠有效下降數據的存儲量,可是由於全局編碼字典須要存儲在內存中,所以在不少時候(海量標籤值),字典所需內存都會很是之大。

上述兩個優化能夠參考OpenTSDB這張經典的示意圖:

 

 

Druid時序數據存儲模型設計

 

和HBase和Kudu這類KV數據庫不一樣,Druid是另外一種玩法。Druid是一個徹徹底底的列式存儲系統,沒有HBase的主鍵。上述時序數據在Druid中表示是下面這個樣子的:

Druid是一個列式數據庫,因此每一列都會獨立存儲,好比Timestamp列會存儲在一塊兒造成一個文件,publish列會存儲在一塊兒造成一個文件,以此類推。細心的童鞋就會說了,這樣存儲,依然會有數據源(tags)大量冗餘的問題。針對冗餘這個問題,Druid和HBase的處理方式同樣,都是採用編碼字典對標籤值進行編碼,將string類型的標籤值編碼成int值。但和HBase不同的是,Druid編碼是局部編碼,Druid和HBase都採用LSM結構,數據先寫入內存再flush到數據文件,Druid編碼是文件級別的,局部編碼能夠有效減少對內存的巨大壓力。除此以外,Druid的這種列式存儲模式還有以下好處:

1. 數據存儲壓縮率高。每列獨立存儲,能夠針對每列進行壓縮,並且能夠爲每列設置對應的壓縮策略,好比時間列、int、fload、double、string均可以分別進行壓縮,壓縮效果更好。

2. 支持多維查找。Druid爲datasource的每一個列分別設置了Bitmap索引,利用Bitmap索引能夠有效實現多維查找,好比用戶想查找20110101T00:00:00這個時間點全部發布在USA的全部廣告的瀏覽量,能夠根據country=USA在Bitmap索引中找到要找的行號,再根據行號定位待查的metrics。

然而,這樣的存儲模型也有一些問題:

問題一:數據依然存在冗餘。和OpenTSDB同樣,tags存在大量的冗餘。

問題二:指定數據源的範圍查找並無OpenTSDB高效。這是由於Druid會將數據源拆開成多個標籤,每一個標籤都走Bitmap索引,再最後使用與操做找到知足條件的行號,這個過程須要必定的開銷。而OpenTSDB中直接能夠根據數據源拼成rowkey,查找走B+樹索引,效率必然會更高。

 

InfluxDB時序數據存儲模型設計

 

相比OpenTSDB以及Druid,可能不少童鞋對InfluxDB並不特別熟悉,然而在時序數據庫排行榜單上InfluxDB倒是遙遙領先。InfluxDB是一款專業的時序數據庫,只存儲時序數據,所以在數據模型的存儲上能夠針對時序數據作很是多的優化工做。

爲了保證寫入的高效,InfluxDB也採用LSM結構,數據先寫入內存,當內存容量達到必定閾值以後flush到文件。InfluxDB在時序數據模型設計方面提出了一個很是重要的概念:seriesKey,seriesKey實際上就是datasource(tags)+metric,時序數據寫入內存以後按照seriesKey進行組織:

 

 

內存中實際上就是一個Map:<SeriesKey, List<Timestamp|Value>>,Map中一個SeriesKey對應一個List,List中存儲時間線數據。數據進來以後根據datasource(tags)+metric拼成SeriesKey,再將Timestamp|Value組合值寫入時間線數據List中。內存中的數據flush的文件後,一樣會將同一個SeriesKey中的時間線數據寫入同一個Block塊內,即一個Block塊內的數據都屬於同一個數據源下的一個metric。

這種設計咱們認爲是將時間序列數據按照時間線挑了出來。先來看看這樣設計的好處:

好處一:同一數據源的tags再也不冗餘存儲。一個Block內的數據都共用一個SeriesKey,只須要將這個SeriesKey寫入這個Block的Trailer部分就能夠。大大下降了時序數據的存儲量。

好處二:時間序列和value能夠在同一個Block內分開獨立存儲,獨立存儲就能夠對時間列以及數值列分別進行壓縮。InfluxDB對時間列的存儲借鑑了Beringei的壓縮方式,使用delta-delta壓縮方式極大的提升了壓縮效率。而對Value的壓縮能夠針對不一樣的數據類型採用相同的壓縮效率。

好處三:對於給定數據源以及時間範圍的數據查找,能夠很是高效的進行查找。這一點和OpenTSDB同樣。

細心的同窗可能會問了,將datasource(tags)和metric拼成SeriesKey,不是也不能實現多維查找。確實是這樣,不過InfluxDB內部實現了倒排索引機制,即實現了tag到SeriesKey的映射關係,若是用戶想根據某個tag查找的話,首先根據tag在倒排索引中找到對應的SeriesKey,再根據SeriesKey定位具體的時間線數據。

InfluxDB的這種存儲引擎稱爲TSM,全稱爲Timestamp-Structure Merge Tree,基本原理相似於LSM。後期筆者將會對InfluxDB的數據寫入、文件格式、倒排索引以及數據讀取進行專題介紹。

InfluxDB能夠稱爲真正的時序數據庫,存儲引擎稱爲TSM,基本架構相似於LSM。數據按照key組織,InfluxDB中key由維度集合加上某一個列值名構成,全部屬於該維度集合加列值的時間序列數值組成的一個集合就掛在該key下。這樣,維度列值就再也不須要冗餘存儲,並且timestamp和point點可使用列式存儲,獨立壓縮。InfluxDB的文件格式以下圖所示:

 

Beringei時序數據存儲模型設計

 

Beringei是今年Facebook開源的一個時序數據庫系統。InfluxDB時序數據模型設計很好地將時間序列按照數據源以及metric挑選了出來,解決了維度列值冗餘存儲,時間列不能有效壓縮的問題。但InfluxDB沒有很好的解決寫入緩存壓縮的問題:InfluxDB在寫入內存的時候並無壓縮,而是在數據寫入文件的時候進行對應壓縮。咱們知道時序數據最大的特色之一是最近寫入的數據最熱,將最近寫入的數據所有放在內存能夠極大提高讀取效率。Beringei很好的解決了這個問題,流式壓縮意味着數據寫入內存以後就進行壓縮,這樣會使得內存中能夠緩存更多的時序數據,這樣對於最近數據的查詢會有很大的幫助。

Beringei的時序數據模型設計與InfluxDB基本一致,也是提出相似於SeriesKey的概念,將時間線挑了出來。但和InfluxDB有兩個比較大的區別:

1. 文件組織形式不一樣。Beringei的文件存儲形式按照時間窗口組織,好比最近5分鐘的數據所有寫入同一個文件,這個文件分爲不少block,每一個block中的全部時序數據共用一個SeriesKey。Beringei文件沒有索引,InfluxDB有索引。

2. Beringei目前沒有倒排索引機制,所以對於多維查詢並不高效。

後續筆者也會針對Beringei的數據寫入、流式壓縮、文件格式等進行介紹。在筆者看來,若是將Beringei和InfluxDB有效結合起來,就可以將時序數據高效存儲在內存,另外數據按照維度進行組織,能夠很是高效的提升數據在文件的存儲效率以及查詢效率,最後結合InfluxDB的倒排索引功能能夠有效提升多維查詢能力。

本文是時序數據庫技術體系的第一篇文章,筆者主要結合OpenTSDB、Druid、InfluxDB以及Beringei這四種時序數據庫分別對時序數據這種數據形式的存儲模型進行了介紹。每種數據庫都有本身的一套存儲方式,而每種存儲方式都有各自的一些優點以及缺陷,正是這些優劣式直接決定了相應時序數據庫的壓縮性能、讀寫性能。

相關閱讀:時序數據庫技術體系(二) : 初識InfluxDB

本文來自網易實踐者社區,經做者範欣欣受權發佈。

相關文章
相關標籤/搜索