1. 程式人生 > >HBase多條件及分頁查詢的一些方法

HBase多條件及分頁查詢的一些方法

nosql數據庫 應用場景 實現簡單 信息 byte 多條 多個 不可用 寫性能

HBase是Apache Hadoop生態系統中的重要一員,它的海量數據存儲能力,超高的數據讀寫性能,以及優秀的可擴展性使之成為最受歡迎的NoSQL數據庫之一。它超強的插入和讀取性能與它的數據組織方式有著密切的關系,在邏輯上,HBase的表數據按RowKey進行字典排序, RowKey實際上是數據表的一級索引(Primary Index),由於HBase本身沒有二級索引(Secondary Index)機制,基於索引檢索數據只能單純地依靠RowKey。也只有使用RowKey查詢數據才能得到非常高的效率。當然,HBase也支持使用其他的字段進行查詢,但是只要沒有RowKey,那麽都是全表掃描。試想一下,在數十億數據中全表掃描是一種什麽樣的體驗,查詢幾乎不可用。而作為數據庫使用,在數據表上的多條件查詢是必然的需求,本文將結合使用經驗,介紹一些常規的HBase的多條件查詢實現方式。

RowKey + Filter的方式

RowKey一般是必不可少的,但是如果數據量少,幾十萬數據,就問題不大。很多時候查詢都會選擇時間,如果能把時間放在RowKey裏面,會極大的提升查詢的效率。這裏有個小技巧:如果Rowkey是按時間戳的方式遞增,不要將時間放在二進制碼的前面,建議將Rowkey的高位作為散列字段,由程序循環生成,低位放時間字段,這樣將提高數據均衡分布在每個Regionserver實現負載均衡的幾率。如果沒有散列字段,首字段直接是時間信息將產生所有新數據都在一個RegionServer上堆積的熱點現象,這樣在做數據檢索的時候負載將會集中在個別RegionServer,降低查詢效率。

HBase的Scan可以通過setFilter方法添加過濾器(Filter),這也是分頁、多條件查詢的基礎。HBase為篩選數據提供了一組過濾器,通過這個過濾器可以在HBase中的數據的多個維度(行,列,數據版本)上進行對數據的篩選操作。通常來說,通過行鍵,值來篩選數據的應用場景較多。這裏簡單舉個例子,使用SingleColumnValueFilter過濾行,查找數據庫中vehicle_speed列是77的數據:

FilterList filterList = new FilterList();
SingleColumnValueFilter scvf = new SingleColumnValueFilter(Bytes.toBytes("f"), Bytes.toBytes("vehicle_speed"), CompareOp.EQUAL, Bytes.toBytes("77"));
filterList.addFilter(scvf);
scan.setFilter(filterList);
ResultScanner scanner 
= table.getScanner(scan);

Filter是可以加多個的,HBase提供十多種Filter類型。filterList.addFilter(scvf) 就是可以添加多個查詢條件,然後調用setFilter函數給Scanner。

這裏再簡單介紹一下分頁的方式:

  • client分頁,scan查到N*M條,過濾掉N*M-M條,返回M條。對於M,N較小時比較適合。
  • 自定義Filter,該filter可以傳遞offset(server端需要過濾的記錄條數),在server端分頁,註意,跨不同的region時需要重新計算該offset
  • 緩存上次分頁查詢的最後一條,下次分頁查詢從這條(不包含)開始查。
  • 查詢條件固定的話,定時任務匯總表
  • PageFilter

使用RowKey + Filter的方式只能滿足一些查詢(數據量少,或者RowKey是必須的參數),包括其分頁的實現並不是最優,但這是使用原生的HBase的方法,比較簡單。下面介紹的方法更好,但是依賴於其他的組件。

Coprocessor

利用Coprocessor協處理器,用戶可以編寫運行在 HBase Server 端的代碼。HBase的Coprocessor分為兩類,Observer和EndPoint。

HBase 支持兩種類型的協處理器,Endpoint 和 Observer。Endpoint 協處理器類似傳統數據庫中的存儲過程,客戶端可以調用這些 Endpoint 協處理器執行一段Server 端代碼,並將 Server 端代碼的結果返回給客戶端進一步處理。

另外一種協處理器叫做Observer Coprocessor,這種協處理器類似於傳統數據庫中的觸發器,當發生某些事件的時候這類協處理器會被 Server 端調用。Observer Coprocessor 就是一些散布在 HBase Server 端代碼中的 hook 鉤子,在固定的事件發生時被調用。比如:put 操作之前有鉤子函數 prePut,該函數在 put 操作執行前會被 Region Server 調用;在 put 操作之後則有 postPut 鉤子函數。

使用Coprocessor來實現簡單的HBase二級索引也是比較常見的方案。但是如果要使用Coprocessor進行二級索引的話,還是推薦下面成熟的方案,它其中也使用到了協處理器。

Phoenix

最早由Salesforce.com開源的Apache Phoenix 是一個Java中間層,可以讓開發者在Apache HBase上執行SQL查詢,目前的版本基本支持常用的操作(分頁,排序,Group By,Having,函數,序列等等)。目前的Phoenix是非常成熟的解決方案,阿裏、Salesforce、eBay等互聯網都在廣泛使用。

Phoenix完全使用Java編寫,代碼位於GitHub上,並且提供了一個客戶端可嵌入的JDBC驅動。它查詢的實時性非常高,一般查詢都在秒級返回,可以應用OLTP的系統中。在用戶必須通過Phoenix來建HBase的表,它會映射到HBase的表上。Phoenix可以創建索引來提升提升多條件查詢HBase的效率。比如,在查詢訂單的時候,可以通過訂單號、時間、狀態等不同的維度來查詢,要想把這麽多角度的數據都放到RowKey中幾乎不可能。而在Phoenix中,你可以針對這幾個字段建立索引。在寫SQL語句的時候,如果Where語句中使用到了這些條件,Phoenix就會自動判斷是否走索引。

Phoenix的索引本質上也是一張HBase的表,它維護了索引和RowKey的關系。在查詢的時候,它會從索引表中先找到RowKey,然後再根據RowKey再去HBase原始數據表中獲取數據。關於Phoenix的二級索引在後續的文章中專門介紹。

Impala

Impala是Cloudera在受到Google的Dremel啟發下開發的實時交互SQL大數據查詢工具,Impala沒有再使用緩慢的Hive+MapReduce批處理,而是通過使用與商用並行關系數據庫中類似的分布式查詢引擎(由Query Planner、Query Coordinator和Query Exec Engine三部分組成),可以直接從HDFS或HBase中用SELECT、JOIN和統計函數查詢數據,從而大大降低了延遲。

Impala目前是Apache的孵化項目。Impala並非是一個OLTP系統,而更像是一個OLAP系統,更加類似於Hive。Impala不能運用在實時系統中,但是如果是針對HBase的統計或者異步查詢的話不妨一試。

ElasticSearch/Solr + HBase

針對HBase使用RowKey訪問超高的效率,我們可以把索引數據放在類似於ElasticSearch或者Solr這樣的搜索引擎裏面。用搜索引擎做二級索引。查詢數據的時候先從搜索引擎中查詢出RowKey,然後再用RowKey去獲取數據。流行的搜索引擎基本可以滿足查詢的所有需求。

舉個例子:訂單數據項有10個,但是用於查詢的有5個。當數據插入HBase的同時,也把這5個數據項加上預先生成的RowKey插入搜索引擎,也就是說部分數據存儲兩份。一份用於搜索,一份用於查詢。大致的架構也許會是這樣:

技術分享

程序A和B分開主要是為了解耦和避免互相影響,當然也可以合並在一個程序裏面。程序A和B也可以是類似於flume或者logstash這樣的組件。

一些建議

在作者的實際經驗中方案的選擇還是要根據數據量和性能要求來選擇。當數據量較小幾十萬,上百萬的話可以使用RowKey+Filter的方式實現。如果數據量到了千萬,甚至億級別,可以嘗試Phoenix。如果數據量到了10億或者更多則需要選擇搜索引擎。同時方案的系統維護難度和對技術的要求也是逐級遞增的。

HBase多條件及分頁查詢的一些方法