HBase二级索引

简介:

我们会经常谈及二级索引,这是对全表数据进行另外一种方式的组织存储,是针对table级别的。如果要为HBase上的表实现一个强一致性的二级索引,那么就无法逃避分布式事务,而这一直是用户最期待的功能。 而即使只需要保证最终一致性,这个索引也并不好实现,因为你需要额外的表以存储过程数据,需要解决宕机恢复问题等
撇开分布式事务,我们是否可以考虑对索引的要求进行降级,比如把Region看成是全表下的子表,实现一套Region级别的索引,通过功能上的牺牲以换取实现的简易及稳定
一般来说,对数据库建立索引,往往需要单独的数据结构来存储索引的数据.在为hbase建立索引时,可以另外建立一张索引表,查询时先查询索引表然后用查询结果查询数据表.

image

但是对于hbase这种分布式的数据库来说,最大的问题是解决索引表和数据表的本地性问题,hbase很容易就因为负载均衡,表split等原因把索引表和数据表的数据分布到不同的region server上,比如下图中,数据表和索引表就出现在了不同的region server上

image

在HBase中实现二级索引与索引Join需要考虑三个目标:
1,高性能的范围检索。
2,数据的低冗余(存储所占的数据量)。
3,数据的一致性。
1,按索引建表
每一个索引建立一个表,然后依靠表的row key来实现范围检索。row key在HBase中是以B+ tree结构化有序存储的,所以scan起来会比较效率。LSM
单表以row key存储索引,column value存储id值或其他数据 ,这就是Hbase索引表的结构。

如何Join?
多索引(多表)的join场景中,主要有两种参考方案:
1,按索引的种类扫描各自独立的单索引表,最后将扫描结果merge。
这个方案的特点是简单,但是如果多个索引扫描结果数据量比较大的话,merge就会遇到瓶颈。

比如,现在有一张1亿的用户信息表,建有出生地和年龄两个索引,我想得到一个条件是在杭州出生,年龄为20岁的按用户id正序排列前10个的用户列表。
有一种方案是,系统先扫描出生地为杭州的索引,得到一个用户id结果集,这个集合的规模假设是10万。
然后扫描年龄,规模是5万,最后merge这些用户id,去重,排序得到结果。
这明显有问题,如何改良?
保证出生地和年龄的结果是排过序的,可以减少merge的数据量?但Hbase是按row key排序,value是不能排序的。
变通一下 – 将用户id冗余到row key里?OK,这是一种解决方案了

image
按索引查询种类建立组合索引。
在方案1的场景中,想象一下,如果单索引数量多达10个会怎么样?10个索引,就要merge 10次,性能可想而知。
解决这个问题需要参考RDBMS的组合索引实现。
比如出生地和年龄需要同时查询,此时如果建立一个出生地和年龄的组合索引,查询时效率会高出merge很多。
当然,这个索引也需要冗余用户id,目的是让结果自然有序。结构图示如下:
image
【协处理器的解决思路】
使用HBase的coprocessor。CoProcessor相当于HBase的Observer+hook,目前支持MasterObserver、RegionObserver和WALObserver,基本上对于HBase Table的管理、数据的Put、Delete、Get等操作都可以找到对应的pre和post。这样如果需要对于某一项Column建立Secondary Indexing,就可以在Put、Delete的时候,将其信息更新到另外一张索引表中。如图二所示,对于Indexing里面的value值是否存储的问题,可以根据需要进行控制,如果value的空间开销不大,逆向的检索又比较频繁,可以直接存储在Indexing Table中,反之则避免这种情况。
image

我们要查询指定店铺指定客户购买的订单,首先有一张订单详情表,它以被处理后的订单id作为rowkey;其次有一张以客户nick为rowkey的索引表,结构如下: 

rowkey family 
dp_id+buy_nick1 tid1:null tid2:null ... 
dp_id+buy_nick2 tid3:null 

public class TestCoprocessor extends BaseRegionObserver {

public void prePut(final ObserverContext<RegionCoprocessorEnvironment> e, 
 final Put put, final WALEdit edit, final boolean writeToWAL) 
 throws IOException { 
     Configuration conf = new Configuration(); 
     HTable table = new HTable(conf, "index_table"); 
     List<Cell> kv = put.get("data".getBytes(), "name".getBytes()); 
     Iterator<Cell> kvItor = kv.iterator(); 
     while (kvItor.hasNext()) { 
         KeyValue tmp = (KeyValue) kvItor.next(); 
         Put indexPut = new Put(tmp.getValue()); 
         indexPut.add("index".getBytes(), tmp.getRow(), Bytes.toBytes(System.currentTimeMillis())); 
         table.put(indexPut); 
     } 
     table.close(); 
 } 

}
即继承BaseRegionObserver类,实现prePut方法,在插入订单详情表之前,向索引表插入索引数据。 
索引表的使用 
先在索引表get索引表,获取tids,然后根据tids查询订单详情表。 
当有多个查询条件(多张索引表),根据逻辑运算符(and 、or)确定tids。 

使用时注意 

1.索引表是一张普通的hbase表,为安全考虑需要开启Hlog记录日志。 
2.索引表的rowkey最好是不可变量,避免索引表中产生大量的脏数据。 
3.如上例子,column是横向扩展的(宽表),rowkey设计除了要考虑region均衡,也要考虑column数量,即表不要太宽。建议不超过3位数。 
4.如上代码,一个put操作其实是先后向两张表put数据,为保证一致性,需要考虑异常处理,建议异常时重试。

put操作效率不高,如上代码,每插入一条数据需要创建一个新的索引表连接(可以使用htablepool优化),向索引表插入数据。即耗时是双倍的,对hbase的集群的压力也是双倍的。当索引表有多个时,压力会更大。 
查询效率比filter高,毫秒级别,因为都是rowkey的查询。 
如上是估计的效率情况,需要根据实际业务场景和集群情况而定,最好做预先测试。 

相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
XML 存储 分布式计算
hbase构建二级索引解决方案
HBase的一级索引就是rowkey,我们仅仅能通过rowkey进行检索。假设我们相对Hbase里面列族的列列进行一些组合查询,就只能全表扫描了。表如果较大的话,代价是不可接受的,所以要提出二级索引的方案。
995 0
hbase构建二级索引解决方案
|
6月前
|
存储 NoSQL 分布式数据库
Hbase的三种索引_全局索引,覆盖索引,本地索引(七)
Hbase的三种索引_全局索引,覆盖索引,本地索引(七)
171 0
|
6月前
|
SQL 分布式数据库 HIVE
Hbase二级索引_Hive on Hbase 及phoenix详解
Hbase二级索引_Hive on Hbase 及phoenix详解
77 0
|
SQL 分布式数据库 Apache
|
分布式数据库 索引 Hbase
《HBase应用与发展之HBase RowKey与索引设计》电子版地址
HBase应用与发展之HBase RowKey与索引设计
122 0
《HBase应用与发展之HBase RowKey与索引设计》电子版地址
|
分布式计算 Hadoop Linux
云计算集群搭建记录[Hadoop|Zookeeper|Hbase|Spark | Docker]更新索引 |动态更新
为了能够更好的查看所更新的文章,讲该博文设为索引 小约定 为了解决在编辑文件等操作的过程中的权限问题,博主一律默认采用root账户登录 对于初次安装的用户可以采用如下命令行:
139 0
云计算集群搭建记录[Hadoop|Zookeeper|Hbase|Spark | Docker]更新索引 |动态更新
|
SQL 搜索推荐 Java
「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践
「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践
541 0
「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践
|
SQL 存储 分布式计算
「从零单排HBase 11」HBase二级索引解决方案
「从零单排HBase 11」HBase二级索引解决方案
182 0
|
SQL 消息中间件 自然语言处理
使用ElasticSearch赋能HBase二级索引 | 实践一年后总结
前言:还记得那是2018年的一个夏天,天气特别热,我一边擦汗一边听领导大刀阔斧的讲述自己未来的改革蓝图。会议开完了,核心思想就是:我们要搞一个数据大池子,要把公司能灌的数据都灌入这个大池子,然后让别人用 各种姿势 来捞这些数据。
1836 0
|
SQL 运维 Java
数据查询的玄铁剑:阿里云HBase二级索引功能解析
HBase原生提供了主键索引,用户可以根据rowkey进行高效的单行读、前缀匹配、范围查询操作。但若需要使用属性列进行查询时,则只能使用filter在查询范围内进行逐行过滤。在扫描范围较大时,会浪费大量的IO,请求RT也无法保证。为此,HBase增强版推出了原生二级索引来解决非rowkey查询的性能问题。
2254 0
数据查询的玄铁剑:阿里云HBase二级索引功能解析