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。异步
这里再简单介绍一下分页的方式:分布式
使用RowKey + Filter的方式只能知足一些查询(数据量少,或者RowKey是必须的参数),包括其分页的实现并非最优,但这是使用原生的HBase的方法,比较简单。下面介绍的方法更好,可是依赖于其余的组件。函数
Coprocessor工具
利用Coprocessor协处理器,用户能够编写运行在 HBase Server 端的代码。HBase的Coprocessor分为两类,Observer和EndPoint。oop
HBase 支持两种类型的协处理器,Endpoint 和 Observer。Endpoint 协处理器相似传统数据库中的存储过程,客户端能够调用这些 Endpoint 协处理器执行一段Server 端代码,并将 Server 端代码的结果返回给客户端进一步处理。post
另一种协处理器叫作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亿或者更多则须要选择搜索引擎。同时方案的系统维护难度和对技术的要求也是逐级递增的。