萬億級日志與行為數據存儲查詢技術剖析——Hbase系預聚合方案、Dremel系parquet列存儲、預聚合系、Lucene系


轉自:http://www.infoq.com/cn/articles/trillion-log-and-data-storage-query-techniques?utm_source=infoq&utm_medium=popular_widget&utm_campaign=popular_content_list&utm_content=homepage

目前大數據存儲查詢方案大概可以分為:Hbase系、Dremel系、預聚合系、Lucene系,筆者就自身的使用經驗說說這幾個系的優缺點,如有紕漏,歡迎一起探討。

數據查詢包括大體可以分為兩步,首先根據某一個或幾個字段篩選出符合條件的數據,然后根據關聯填充其他所需字段信息或者聚合其他字段信息,本文中提到的大數據技術,都將圍繞這兩方面。

一、Hbase系

 

筆者認為Hbase系的解決方案(例如Opentsdb和Kylin)適合相對固定的業務報表類需求,只需要統計少量維度即可滿足業務報表需求,對於單值查詢有優勢,但很難滿足靈活聚合數據的場景。

而在需要聚合的場景,對於Hbase而言恰恰需要大量scan數據,會非常影響性能。Hbase只有一個簡單rowkey的倒排索引,缺少列索引,所有的查詢和聚合只能依賴於rowkey,很難解決聚合的性能問題。

隨着Hbase的發展,基於Hbase做數據存儲包括Opentsdb和Kylin也隨之產生,例如Kylin也是一種預聚合方案,因其底層存儲使用Hbase,故筆者將其歸為Hbase系。在筆者看來,Opentsdb和Kylin的數據結構極其相似,都是將各種維度值組合,結合時間戳拼成rowkey,利用字典的原理將維度值標簽化,達到壓縮的目的。如此,可以滿足快速查詢數據的需要,但同時也會受限於Hbase索引,聚合需要大量scan,並不能提升數據聚合的速度。

為了避免查詢數據時的聚合,Kylin可以通過cube的方式定制數據結構,在數據接入時通過指定metric來提前聚合數據。這樣雖然在一定程度上解決了數據聚合慢的情況,但這是一種典型的空間換時間的方案,組合在維度多、或者有高基數維度的情況,數據膨脹會非常嚴重,筆者曾遇到存儲后的數據比原始數據大90倍的情況。另外,業務的變化會導致重建cube,難以靈活的滿足業務需要。

二、Dremel系

Parquet作為Dremel系的代表,相對Hbase的方案,Scan的性能更好,也避免了存儲索引和生成索引的開銷。但對於數據還原和聚合,相對直接使用正向索引來說成本會很高,而且以離線處理為主,很難提高數據寫的實時性。

Google的Dremel,其最早用於網頁文檔數據分析,所以設計為嵌套的數據結構,當然它也可以用於扁平的二維表數據存儲。開源技術中,Parquet算是Dremel系的代表,各種查詢引擎(Hive/Impala/Drill)、計算框架甚至一些序列化結構數據(如ProtoBuf)都對其進行了支持,甚至Spark還專門針對Parquet的數據格式進行了優化,前途一片光明,本文主要結合Parquet來展開論述。

Parquet的實時寫方面是硬傷,基於Parquet的方案基本上都是批量寫。一般情況,都是定期生成Parquet文件,所以數據延遲比較嚴重。為了提高數據的實時性,還需要其他解決方案來解決數據實時的查詢,Parquet只能作為歷史數據查詢的補充。

Parquet存儲是相對索引的存儲來說,是一種折中處理,沒有倒排索引,而是通過Row Group水平分割數據,然后再根據Column垂直分割,保證數據IO不高,直接Scan數據進行查詢,相對Hbase的方案,Scan的性能更好。這種方式,避免了存儲索引和生成索引的開銷,隨着索引Page的完善,相信查詢性能值得信賴。而對於數據還原和聚合也沒有利用正向索引,而是通過Striping/Assembly算法來解決,這種方式更好能夠很取巧的解決數據嵌套填充的問題, 但是相對直接使用正向索引來說成本會很高。

另外,由於是基於Row Group為讀寫的基本單元,屬於粗粒度的數據寫入,數據生成應該還是以離線處理為主,很難提高數據寫的實時性,而引入其他的解決方案又會帶來存儲架構的復雜性,維護成本都會相應增加。

三、預聚合系

最近幾年,隨着OLAP場景的需要,預聚合的解決方案越來越多。其中比較典型的有Kylin、Druid和Pinot。預聚合的方案,筆者不想做過多介紹,其本身只是單純的為了滿足OLAP查詢的場景,需要指定預聚合的指標,在數據接入的時候根據指定的指標進行聚合運算,數據在聚合的過程中會丟失metric對應的列值信息。

筆者認為,這種方式需要以有損數據為代價,雖然能夠滿足短期的OLAP需求,但是對於數據存儲是非常不利的,會丟掉數據本身存在的潛在價值。另外,查詢的指標也相對固定,沒有辦法靈活的自由定義所需的指標,只能查詢提前聚合好的指標。

四、Lucene系

Lucene算是java中最先進的開源全文檢索工具,基於它有兩個很不錯的全文檢索產品ElasticSearch和Solr。Lucene經過多年的發展,整個索引體系已經非常完善,能夠滿足的的查詢場景遠多於傳統的數據庫存儲,這都歸功於其強大的索引。但對於日志、行為類時序數據,所有的搜索請求都也必須搜索所有的分片,另外,對於聚合分析場景的支持也是軟肋。

Lucene中把一條數據對應為一個Document,數據中的字段對應Lucene的Field,Field的信息可以拆分為多個Term,同時Term中會包含其所屬的Field信息,在Lucene中每一個Document都會分配一個行號。然后在數據接入時建立Term和行號的對應關系,就能夠根據字段的信息快速的搜索出相應的行號,而Term與行號的對應關系我們稱之為字典。大部分時候查詢是多個條件的組合,於是Lucene引入了跳表的思想,來加快行號的求交和求並。字典和跳表就共同組成了Lucene的倒排索引。Lucene從4開始使用了FST的數據結構,即得到了很高的字典壓縮率,又加快了字典的檢索。

由於ElasticSearch是一個搜索框架,對於所有的搜索請求,都必須搜索所有的分片。對於一個針對內容的搜索應用來說,這顯然沒有什么問題,因為對應的內容會被存儲到哪一個分片往往是不可知的。然而對於日志、行為類數據則不然,因為很多時候我們關注的是某一個特定時間段的數據,這時如果我們可以針對性的搜索這一部分數據,那么搜索性能顯然會得到明顯的提升。

同時,這類數據往往具有另一個非常重要的特征,即時效性。很多時候我們的需求往往是這樣的:對於最近一段時間的熱數據,其查詢頻率往往要比失去時效的冷數據高得多,而ElasticSearch這樣不加區分的分片方式顯然不足以支持這樣的需求。

而另外一方面,ElasticSearch對於聚合分析場景的支持也是軟肋,典型的問題是,使用Hyperloglog這類求基數的聚合函數時,非常容易發生oom。這固然跟這類聚合算法的內存消耗相對高有關(事實上,hll在基數估計領域是以內存消耗低著稱的,高是相對count,sum這類簡單聚合而言)。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM