`
kirayuan
  • 浏览: 39763 次
文章分类
社区版块
存档分类
最新评论

hbase二级索引

 
阅读更多

二级索引与索引Join是多数业务系统要求存储引擎提供的基本特性,RDBMS早已支持,NOSQL阵营也在摸索着符合自身特点的最佳解决方案。
这篇文章会以HBase做为对象来讨论如何基于Hbase构建二级索引与实现索引join。文末同时会列出目前已知的包括0.19.3版secondary index,ITHbase, Facebook方案和官方Coprocessor的介绍。

理论目标
在HBase中实现二级索引与索引Join需要考虑三个目标:
1,高性能的范围检索。
2,数据的低冗余(存储所占的数据量)。
3,数据的一致性。

性能与数据冗余,一致性是相互制约的关系。
如果你实现了高性能地范围检索,必然需要靠冗余索引数据来提升性能,而数据冗余会导致更新数据时难以实现一致性,特别是分布式场景下。
如果你不要求高效地范围检索,那么可以不考虑产生冗余数据,一致性问题也可以间接避免,毕竟share nothing是公认的最简单有效的解决方案。

理论结合实际,下文会以实例的方式来阐述各个方案是如何选择偏重点。
这些方案是经过笔者资料查阅和同事的不断交流后得出的结论,如有错误,欢迎指正:

1,按索引建表
每一个索引建立一个表,然后依靠表的row key来实现范围检索。row key在HBase中是以B+ tree结构化有序存储的,所以scan起来会比较效率。
单表以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,这是一种解决方案了,这个方案的图示如下:

merge时提取交集就是所需要的列表,顺序是靠索引增加了_id,以字典序保证的。

2, 按索引查询种类建立组合索引。
在方案1的场景中,想象一下,如果单索引数量多达10个会怎么样?10个索引,就要merge 10次,性能可想而知。


解决这个问题需要参考RDBMS的组合索引实现。
比如出生地和年龄需要同时查询,此时如果建立一个出生地和年龄的组合索引,查询时效率会高出merge很多。
当然,这个索引也需要冗余用户id,目的是让结果自然有序。结构图示如下:

这个方案的优点是查询速度非常快,根据查询条件,只需要到一张表中检索即可得到结果list。缺点是如果有多个索引,就要建立多个与查询条件一一对应的组合索引,存储压力会增大。

在制定Schema设计方案时,设计人员需要充分考虑场景的特点,结合方案一和二来使用。下面是一个简单的对比:

单索引 组合索引
检索性能 优异 优异
存储 数据不冗余,节省存储。 数据冗余,存储比较浪费。
事务性 多个索引保证事务性比较困难。 多个索引保证事务性比较困难。
join 性能较差 性能优异
count,sum,avg,etc 符合条件的结果集全表扫描 符合条件的结果集全表扫描

从上表中可以得知,方案1,2都存在更新时事务性保证比较困难的问题。如果业务系统可以接受最终一致性的话,事务性会稍微好做一些。否则只能借助于复杂的分布式事务,比如JTA,Chubby等技术。
count, sum, avg, max, min等聚合功能,Hbase只能通过硬扫的方式,并且很悲剧,你可能需要做一些hack操作(比如加一个CF,value为null),否则你在扫描时可能需要往客户端传回所有数据。
当然你可以在这个场景上做一些优化,比如增加状态表等,但复杂性带来的风险会更高。
还有一种终极解决方案就是在业务上只提供上一页和下一页,这或许是最简单有效的方案了。

2,单张表多个列族,索引基于列
Hbase提供了列族Column Family特性。
列索引是将Column Family做为index,多个index值散落到Qualifier,多个column值依据version排列(CF, Qualifer, Version Hbase会保证有序,其中CF和Qualifier正序,Version倒序)。

举个典型的例子,就是用户卖了很多商品,这些商品的标题title需要支持like %title%查询。传统基于RDMBS就是模糊查询,基于search engine就是分词+倒排表。
在HBase中,模糊查询显然不满足我们的要求,接下来只能通过分词+倒排的方式来存储。基于CF的倒排表索引结构见下图:

取数据的时候,只需要根据用户id(row key)定位到一个row,然后根据分词定位到qualifier,再通过version的有序list,取top n条记录即可。不过大家可能会发现个问题,version list的总数量是需要scan全version list才能知道的,这里需要业务系统本身做一些改进。

如何join?
实现方式同方案1里的join,多个CF列索引扫描结果后,需要走merge,将多个索引的查询结果conjunction。

两个方案的对比似乎变化就是一个表,一个列,但其实这个方案有个最大的好处,就是解决了事务性的问题,因为所有的索引都是跟单个row key绑定的,我们知道单个row的更新,在hbase中是保证原子更新的,这就是这个方案的天然优势。当你在考虑单索引时,使用基于列的索引会比单表索 引有更好的适用性。
而组合索引在以列为存储粒度的方案里,也同样可以折中实现。理解这种存储模式的同学可能已经猜到了,就是基于qualifier。

下表对比了表索引和列索引的优缺点:

列索引 表索引
检索性能 检索数据需要走多次scan,第一次scan row key,第二次scan qualifier,第三次scan version。 只需要走一次row key的scan即可。
存储 在没有组合索引时,存储较节省 在没有组合索引时,存储较节省
事务性 容易保证 保证事务性比较困难
join 性能较差,只有在建立组合条件Qualifier的时候性能会有所改善 性能较差,只有在建立组合表索引的时候性能会有所改善
额外的问题 1,同一个row里每个qualifier的version是有大小限制的,不能超过Int的最大值。(别以为这个值很大,对于海量数据存储,上亿很平常)
2,version的count总数需要额外做处理获取。
3,单个row数据超过split大小时,会导致不能compaction或compaction内存吃紧,增加风险。
count,sum,avg,etc 符合条件的结果集全表扫描 符合条件的结果集全表扫描

虽然列索引缺点这么多,但是存储节省带来的成本优势有时还是值得我们去这么做的,何况它还解决了事务性问题,需要用户自己去权衡。
值得一提的是,Facebook的消息应用服务器就是基于类似的方案来实现的。

3,ITHBase
方案一中的多表,解决了性能问题,同时带来了存储冗余和数据一致性问题。这两个问题中,只要解决其中一项,其实也就满足了大多数业务场景。
本方案中,着重关注的是数据一致性。ITHbase的全称是 Indexed Transactional HBase,从名字中就能看出,事务性是它的重要特性。

ITHBase的事务原理简介
建一张事务表__GLOBAL_TRX_LOG__,每次开启事务时,在表中记录状态。因为是基于Hbase的HTable,事务表同样会写WAL用于恢复,不过这个日志格式被ITHbase改造过,它称之为THLog。
客户端对多张表更新时,先启动事务,然后每次PUT,将事务id传递给HRegionServer。
ITHbase通过继承HRegionServer和HReogin类,重写了大多数操作接口方法,比如put, update, delete, 用于获取transactionalId和状态。
当server收到操作和事务id后,先确认服务端收到,标记当前事务为待写入状态(需要再发起一次PUT)。当所有表的操作完成后,由客户端统一做commit写入,做二阶段提交。

4,Map-reduce
这个方案没什么好说的,存储节省,也不需要建索引表,只需要靠强大的集群计算能力即可导出结果。但一般不适合online业务。

5,Coprocessor协处理器
官方0.92.0新版正在开发中的新功能-Coprocessor,支持region级别索引。详见:
https://issues.apache.org/jira/browse/HBASE-2038

协处理器的机制可以理解为,server端添加了一些回调函数。这些回调函数如下:

The Coprocessor interface defines these hooks:

  • preOpen, postOpen: Called before and after the region is reported as online to the master.
  • preFlush, postFlush: Called before and after the memstore is flushed into a new store file.
  • preCompact, postCompact: Called before and after compaction.
  • preSplit, postSplit: Called after the region is split.
  • preClose and postClose: Called before and after the region is reported as closed to the master.

The RegionObserver interface is defines these hooks:

  • preGet, postGet: Called before and after a client makes a Get request.
  • preExists, postExists: Called before and after the client tests for existence using a Get.
  • prePut and postPut: Called before and after the client stores a value.
  • preDelete and postDelete: Called before and after the client deletes a value.
  • preScannerOpen postScannerOpen: Called before and after the client opens a new scanner.
  • preScannerNext, postScannerNext: Called before and after the client asks for the next row on a scanner.
  • preScannerClose, postScannerClose: Called before and after the client closes a scanner.
  • preCheckAndPut, postCheckAndPut: Called before and after the client calls checkAndPut().
  • preCheckAndDelete, postCheckAndDelete: Called before and after the client calls checkAndDelete().

利用这些hooks可以实现region级二级索引,实现count, sum, avg, max, min等聚合操作而不需要返回所有的数据,详见 https://issues.apache.org/jira/browse/HBASE-1512

二级索引的原理猜测
因为coprocessor的最终方案还未公布,就提供的这些hooks来说,二级索引的实现应该是拦截同一个region的put, get, scan, delete等操作。与此同时在同一个reigon里维护一个索引CF,建立对应的索引表。
基于region的索引表其实有很多局限性,比如全局排序就很难做。

不过我觉得Coprocessor最大的好处在于其提供了server端的完全扩展能力,这对于Hbase来说是一个大的跃进。

如何join?

目前还未发布,不过就了解很难从本质上有所突破。解决方案无非就是merge和composite index,同样事务性是需要解决的难题之一。

业界已经公开的二级索引方案罗列:

0.19.3版Secondary Index

一直关注HBase的同学,或许知道,早在HBase 0.19.3版发布时,曾经加入过secondary index的功能,Issue详见这里
它的使用例子也很简单:http://blog.rajeevsharma.in/2009/06/secondary-indexes-in-hbase.html

0.19.3版Secondary Index通过将列值以row key方法存储,提供索引scan。
但HBase早期的需求主要来自Hadoop。事务的复杂性以及当时发现hadoop-core里有个很难解决的与ITHBase兼容的问题,致使官方在0.20.0版将其核心代码移出了hbase-core,改为contrib第三方扩展,Issue详见这里

Transactional tableindexed-ITHBase

这个方案就是在0.19.3版被官方剥离出核心的第三方扩展,它的方案上面已经介绍过了。目前支持最新的Hbase 0.90。
是否具备工业强度的稳定性是用户选择它的主要障碍。

https://github.com/hbase-trx/hbase-transactional-tableindexed

Facebook方案

facebook采用的是单表多列索引的解决方案,上面已经提到过了。很完美地解决了数据一致性问题,这主要跟他们的使用场景有关。


感兴趣的同学可以看下这篇blog,本文不作详述:

blog.huihoo.com/?p=688

HBase官方方案 0.92.0 版开发中 – Coprocessor协处理器

还未发布,不过hbase官方blog有篇介绍:http://hbaseblog.com/2010/11/30/hbase-coprocessors

Lily Hbase indexing Library

这是一个索引构建,查询,管理的框架。结构上,就是通过一张indexmeta表管理多张indexdata索引表。
特点是,有一套非常完善的针对int, string, utf-8, decimal等类型的row key排序机制。这个机制在这篇博文中有详细介绍:

http://brunodumon.wordpress.com/2010/02/17/building-indexes-using-hbase-mapping-strings-numbers-and-dates-onto-bytes/

此外,框架针对join场景(原理=merge),提供了封装好的conjunction和disjunction工具类。
针对索引构建场景,Hbase indexing library也提供了很方便的接口。

IHbase

IHBase非常类似ITHBase。
IHBase同样从HBase源码级别进行了扩展了,重新定义和实现了一些Server,Client端处理逻辑,所以,它是具备强侵入性的。
不幸的是,这个工具在fix完Hbase 0.20.5版兼容bug以后再也没更新。是否支持0.90以上版本,笔者还未尝试。
IHBase与ITHBase的一个对比(仁者见仁)
Feature ITHBase IHBase Comment
global ordering yes no IHBase has an index for each region. The flip side of not having global ordering is compatibility with the good old HRegion: results are coming back in row order (and not value order as in ITHBase)
Full table scan? no no THbase does a partial scan on the index table. ITHBase supports specifying start/end rows to limit the number of scanned regions
Multiple Index Usage no yes IHBase can take advantage of multiple indexes in the same scan. IHBase IdxScan object accepts an Expression which allows intersection/unison of several indexed column criteria
Extra disk storage yes no IHBase indexes are created when the region starts/flushes and do not require any extra storage
Extra RAM yes yes IHBase indexes are in memory and hence increase the memory overhead. THBbase indexes increase the number of regions each region server has to support thus costing memory too
Parallel scanning support no yes In ITHBase the index table needs to be consulted and then GETs are issued for each matching row. The behavior of IHBase (as perceived by the client) is no different than a regular scan and hence supports parallel scanning seamlessly.parallel GET can be implemented to speedup THbase scans
原理简介
在Memstore满了以后刷磁盘时,IHBase会进行拦截请求并为这个memstore的数据构建索引。索引另一个CF的方式存储在表内。不过只支持region级别(类似coprocessor)
scan的时候,IHBase会结合索引列中的标记,来加速scan。
http://github.com/ykulbak/ihbase

转:http://kenwublog.com/hbase-secondary-index-and-join
分享到:
评论

相关推荐

    HBase二级索引

    HBase 二级索引 HBase 二级索引是指在 HBase 之上建立的一种二级索引机制,用于提高查询效率。根据华为公布的 HBase 二级索引实现方案,本方案主要参照了该方案,设计了 HBase 的二级索引机制。 知识点一:HBase ...

    奇虎360 HBASE 二级索引的设计与实践

    奇虎360 HBASE二级索引的设计与实践内容总结: 背景介绍: 在奇虎360的实际应用中,仅通过Rowkey(RK)进行索引存在一系列问题。例如,索引较为单一,无法满足多维度查询需求,例如字段或列的多维度查询。此外,...

    CDH使用Solr实现HBase二级索引.docx

    CDH 使用 Solr 实现 HBase 二级索引 在大数据处理中,HBase 是一种流行的 NoSQL 数据库,用于存储大量的数据。然而,在查询和检索数据时,HBase 的性能可能不太理想。这是因为 HBase 是基于 Key-Value 的存储方式,...

    360HBASE二级索引的设计与实践

    ### 360HBASE二级索引的设计与实践 #### 背景 在大数据处理领域,特别是面对海量数据(如千亿级别的数据量)时,高效的数据存储与快速查询成为了关键的技术挑战之一。HBase作为一种分布式、面向列的NoSQL数据库...

    Hbase二级索引与JOIN

    ### HBase二级索引与JOIN知识点详解 #### HBase简介 - **定义**: HBase是一种分布式、面向列的NoSQL数据库系统,它基于Google Bigtable论文实现。 - **底层架构**: HBase的数据存储依赖于Hadoop Distributed File ...

    HBase二级索引实现方案

    本方案主要参照了华为公布的HBase二级索引实现方案。为每个DataTable创建一个与之对应的IndexTable,通过各种途径,保证IndexTable Region与DataTable Region一一对应,并且存储在同一个RegionServer上。

    基于协处理器的HBase二级索引方法.pdf

    针对这一问题,本文提出了一种创新性的解决方案——基于协处理器(Coprocessor)的HBase二级索引方法。协处理器是一种嵌入在HBase服务器端的自定义代码,它可以在数据读写过程中执行用户定义的操作,为HBase提供了...

    hbase+solr创建二级索引完整操作

    ### hbase+solr创建二级索引完整操作 #### 一、概述 本文档详细介绍了如何利用HBase和Solr创建二级索引的过程。通过整合HBase与Solr的优势,可以构建高性能的数据存储与检索系统。HBase作为分布式列族数据库,能够...

    hbaseSecondaryIndex:hbase二级索引实现

    hbaseSecondaryIndex是一个hbase二级索引的实现,基于solr+hbase coprocessor框架为hbase提供索引表支持。 此工程可打包为一个hbase的插件,通用方便。 这篇文档的目的是为了向您介绍hbaseSecondaryIndex的基本使用...

    HBase分布式二级索引通用方案研究.pdf

    文章指出,部署这一通用方案后,实验结果表明,该方案能够很好地满足创建和维护HBase二级索引的要求,并且能够保证索引与记录的一致性。这表明,该方案在实践中具有很好的可行性和效果,对于进一步研究分布式存储中...

    基于协处理器的HBase分类二级索引设计.pdf

    在实施基于协处理器的HBase二级索引设计时,应参考相关的技术文档和最佳实践,例如《HBase: The Definitive Guide》等专业书籍。此外,社区论坛和官方文档也是获取最新信息和解决问题的重要资源。在实际项目中,还...

    hbase-solr-coprocessor:通过solr实现hbase二级索引,主要通过hbase的coprocessor的Observer实现

    测试代码,目的是借助solr实现hbase二级索引,以使hbase支持高效的多条件查询。主要通过hbase的coprocessor的Observer实现,通过coprocessor在记录插入hbase时向solr中创建索引。 项目核心为...

    HBase二级索引 简易理解

    一、解决的问题 1、RowKey 例子 ...二、对于上面需求 简单解决方案(二级索引 相当于添加一层映射关系到 原RowKey) 增加新的Hbase表 RowKey:hive_table__date___date__hive_table (解释:hive_tabl

    基于phoenix的Hbase二级全文索引方法及系统.pdf

    "基于phoenix的Hbase二级全文索引方法及系统" 本文主要介绍了基于phoenix的Hbase二级全文索引方法及系统,旨在解决Hbase数据的全文检索问题。该方法包括两大步骤:一是对Hbase原始数据表建立二级全文索引表,并存储...

    HBase_Secondary_Index

    具体来看,“HadoopDevelopment•SecondaryIndexinHBase”揭示了HBase二级索引是华为Hadoop R&D团队关注的重点开发领域之一。此外,文档中提到了HDFS NNHA(Hadoop-2),这是一个高可用的NameNode设计,对于HBase的...

Global site tag (gtag.js) - Google Analytics