時間序列數據庫的祕密(1)—— 介紹

什麼是時間序列數據?最簡單的定義就是數據格式裏包含timestamp字段的數據。比如股票市場的價格,環境中的溫度,主機的CPU使用率等。但是又有什麼數據是不包含timestamp的呢?幾乎所有的數據都可以打上一個timestamp字段。時間序列數據更重要的一個屬性是如何去查詢它。在查詢的時候,對於時間序列我們總是會帶上一個時間範圍去過濾數據。同時查詢的結果裏也總是會包含timestamp字段。

選擇什麼樣的時間序列數據庫

時間序列數據無處不在。而幾乎任意數據庫都可以存時間序列數據。但是不同的數據能支持的查詢類型並不相同。按照能支持的查詢類型,我們可以把時間序列數據庫分爲兩類,第一類的數據庫按照關係型數據庫的說法,其表結構是這樣的:

[metric_name] [timestamp] [value]

其優化的查詢方式是:

SELECT value FROM metric WHERE metric_name=”A” AND timestamp >= B AND timestamp < C

也就說這類數據庫是什麼樣子的數據存進去,就什麼樣子取出來。

在這種模式下,首先要知道你需要的圖表是什麼樣子的。然後按照這個圖表的數據,去把數據入庫。查詢的字段,就是數據庫存儲的字段。然後再按照數據庫存儲的字段,去從原始數據裏採集上報。存儲什麼字段,就上報什麼字段。這種模式很容易優化,可以做到非常快。但是這種模式有兩個弊端。

  • 無法快速響應變化:如果需要的圖表有變更,需要從上報的源頭重新來一遍。而且要等新數據過來之後,才能查看這些新數據。
  • 存儲膨脹:總有一些數據是需要從不同維度查詢的要求。比如廣告點擊流數據,需要按省份聚合,按運營商聚合,按點擊人的喜好聚合等。這些維度的交叉組合會產生非常巨大的組合數量,要預先把所有的維度組合都變成數據庫裏的表存儲起來會很浪費空間。

這類時間序列數據庫最多,使用也最廣泛。一般人們談論時間序列數據庫的時候指代的就是這一類存儲。按照底層技術不同可以劃分爲三類。

另外一類數據庫其表結構是:

[timestamp] [d1] [d2] .. [dn] [v1] [v2] .. [vn]

其優化的查詢方式不限於查詢原始數據,而是可以組合查詢條件並且做聚合計算,比如:

SELECT d2, sum(v1) / sum(v2) FROM metric WHERE d1 =
 “A” AND timestamp >= B AND timestamp < C GROUP BY d2

我們希望時間序列數據庫不僅僅可以提供原始數據的查詢,而且要支持對原始數據的聚合能力。這種聚合可以是在入庫階段完成的,所謂物化視圖。也可以是在查詢階段完成,所謂實時聚合。根據實際情況,可以在這兩種方式中進行取捨。

想要在在查詢階段做數據的聚合和轉換,需要能夠支持以下三點。

  • 用索引檢索出行號:能夠從上億條數據中快速過濾出幾百萬的數據。
  • 從主存儲按行號加載:能夠快速加載這過濾出的幾百萬條數據到內存裏。
  • 分佈式計算:能夠把這些數據按照GROUP BY 和 SELECT 的要求計算出最終的結果集。

要想儘可能快的完成整個查詢過程,需要在三個環節上都有絕招。傳統上說,這三個步驟是三個不同的技術領域。

  • 檢索:這是搜索引擎最擅長的領域。代表產品是Lucene。其核心技術是基於高效率數據結構和算法的倒排索引。
  • 加載:這是分析型數據庫最擅長的領域。代表產品是C-storeMonetdb。其核心技術是按列組織的磁盤存儲結構。
  • 分佈式計算:這是大數據計算引擎最擅長的領域。代表產品是Hadoopspark。其核心技術是sharding 和 map/reduce等等。

前面提到的時間序列庫(比如opentsdb)有不少從功能上來說是沒有問題。它們都支持過濾,也支持過濾之後的聚合計算。在數據量小的時候勉強是可用的。但是如果要實時從十億條裏取百萬記錄出來,再做聚合運算,對於這樣的數據量可能就勉爲其難了。滿足海量數據實時聚合要求的數據庫不多,比較常見的有這麼幾種:

其中Elasticsearch是目前市場上比較很少有的,能夠在檢索加載和分佈式計算三個方面都做得一流的數據庫。而且是開源並且免費的。它使用了很多技術來達到飛一般的速度。這些主要的優化措施可以列舉如下。

  • Lucene的inverted index可以比mysql的b-tree檢索更快。
  • 在 Mysql中給兩個字段獨立建立的索引無法聯合起來使用,必須對聯合查詢的場景建立複合索引。而lucene可以任何AND或者OR組合使用索引進行檢索。
  • Elasticsearch支持nested document,可以把一批數據點嵌套存儲爲一個document block,減少需要索引的文檔數。
  • Opentsdb不支持二級索引,只有一個基於hbase rowkey的主索引,可以按行的排序順序scan。這使得Opentsdb的tag實現從檢索效率上來說很慢。
  • Mysql 如果經過索引過濾之後仍然要加載很多行的話,出於效率考慮query planner經常會選擇進行全表掃描。所以Mysql的存儲時間序列的最佳實踐是不使用二級索引,只使用clustered index掃描主表。類似於Opentsdb。
  • Lucene 從 4.0 開始支持 DocValues,極大降低了內存的佔用,減少了磁盤上的尺寸並且提高了加載數據到內存計算的吞吐能力。
  • Lucene支持分segment,Elasticsearch支持分index。Elasticsearch可以把分開的數據當成一張表來查詢和聚合。相比之下Mysql如果自己做分庫分表的時候,聯合查詢不方便。
  • Elasticsearch 從1.0開始支持aggregation,基本上有了普通SQL的聚合能力。從 2.0 開始支持 pipeline aggregation,可以支持類似SQL sub query的嵌套聚合的能力。這種聚合能力相比Crate.io,Solr等同門師兄弟要強大得多。

後面我們分爲兩篇文章用科普的方式,具體來看看Elasticsearch是基於什麼原理如何做到比mysql和opentsdb更快地查詢和聚合時間序列數據的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章