Hbase使用经验总结 - ZhaoHongnan/Introductiion-To-Hbase GitHub Wiki

一、基础概念

1.Hbase

Hbase基于Apache Hadoop的应用,是谷歌Bigtable的开源实现,运行在HDFS文件系统之上。尤其适合于存储海量洗漱的数据。

2.表(table)

Hbase数据访问和存储通过表进行。数据存储在数据表中,没有数据类型,全部作为字节处理。数据表中的数据存储在HDFS文件系统中。

3.行(row)

rowkey是行的唯一标示,同样不具有数据类型,按照字典顺序排序,Hbase分表时按照行进行负载。在Hbase中按行加锁,因此单行操作具有事务性,多行操作不具有事务性。

4.列族(column family)

列族是列的集合的概念,一个列族包含有多个列。列族影响着Hbase中的物理存储,在表中每行数据即使部分列族没有数据仍会具有相同的列族,这点与列(column qualifier)不同,但是类似于mysql数据库中列。在定义表时,列族需要一起指定,之后不可以修改。

5.列(column qualifier)

列属于某一个列族中,不需要提起确定,在数据写入时可以动态增加,所以不同的行可以具有不同的列。

6.单元(cell)

Hbase中存储数据的最小单位。每个单元数据都具有一个写入时的时间戳,不同版本的值按照时间戳排序,这样最新版本的数据总可以先读到。单元中数据value被赋值之后可以由rowkey,列族,列和时间戳查询。

二、Master节点与Regionserver节点

1.Hbase主从模式

Hbase采用与Mapreduce和HDFS相同的主从模式,一个master节点协调管理一个或多个regionserver。

2.Master节点

master负责分片region到regionserver,检查新增和过期的regionserver,平衡regionserver负载等。region是由表水平划分而成,每个region由表中行的子集构成,每个区域由它所属于的表,所包含的第一行及其最后一行(不包括这行)来表示。region是数据分布的最小单元。

3.Regionserver节点

regionserver负载管理零到多个region,响应客户端读写请求,操作region,分表等。

4.客户端

客户端直接与regionserver交互读写请求,不与master交互。

三、查找分区(region location)

Hbase依赖Zookeeper维护系统的分布式管理。在查找region利用三层级树状目录检索,在Zookeeper相应目录中保留名为-ROOT-和.META.的特殊目录表。它们保存有当前集群上所有region的位置信息和状态等。-ROOT-表包含.META.表的region列表,而.META.表包含用户空间region列表(user space region)。当user space region发生分裂,删除等操作时目录会进行相应更新。在实践中,千万数量级的Hbase表按照三级目录检索rowkey可以在1s内返回结果,因此对于某些对返回时间要求不严格的应用可以直接访问Hbase。

四、Regionserver读写请求

1.读请求

当客户端发出读请求时,首先查找-ROOT-的位置,然后通过-ROOT-获取请求行所属.META.表的位置,最后通过.META.获取用户空间表所在节点及其位置。接着,客户端与管理用户表空间regionserver交互。为了节省访问Zookeeper节点的代价,客户端会缓存-ROOT-和.META.等目录表信息。

2.写请求

当客户端发出写请求时,到达regionserver后先追加写入到提交日志(commit log),然后写入到叫做memstore的内存中,当memstore存满时,刷(flush)到文件系统中。在这里当regionserver出现故障,memstore内存内容不存在,但是提交日志仍然可用,之后分配到其他region中重做(replay)。

3.读请求与regionserver交互

读请求到达regionserver之后先查看memstore中是否存在数据,如果没有才查询文件系统。

五、优化

1.列族要小

因为Hbase中每一列都属于一个列族中,当访问Hbase数据列时都会返回对应的列族信息,如果列族字符串很长,在数据量很大的情况下会导致占用极大的网络资源影响操作Hbase的效率。因此对于数据列族使用简单的一个字母作为列族名即可,同样列也尽量在可以表达含义的基础上减少字符。

2.rowkey设计

rowkey是查询行的唯一标识,负载时分配region又是以行为基础。rowkey的设计直接关系到region的热点情况,如果查询量大的rowkey集中在少数一个或几个region上,那么这些region就会成为热点。依据空间局部性理论,在一些特定业务中,如果某条数据被访问那么它附近的数据很可能很快会被访问。最简单的解决方法是使用md5将相互类似属性的数据分散存储在不同region中。另外,rowkey的设计有时候也要便于成块查找,例如某个用户id在某段时间的数据,那么不仅仅要将用户id作为rowkey的一部分还需要将时间放入rowkey中,而且用户id在前,对于使用java api访问时可以使用区间查询的api接口。

3.利用Hbase行锁性质

在数据操作时常常会遇到多线程操作的情况,在多线程环境中可能引起脏数据问题,就是因为多线程执行完成的时间不可控导致旧数据覆盖新数据。我们可以在程序中加入本地锁或者分布式锁,但有些时候问题处理或许可以更简单,就是利用数据库的锁。Hbase保证行操作是事务性的,也就是说只要我们可以控制相同rowkey逐条访问即可保证数据正确行。在java中利用线程池,或者对rowkey字符串加锁,或者利用队列的先进先出性质保证rowkey有序等。

4.布隆过滤器过滤

在实践中,对于直接访问Hbase的情况比较常见,Hbase是基于大数据处理设计的,相较于其他访问快速的数据库而言,访问数据性能较差。对于返回时间要求尽可能快,而且不存在的数据较多的服务,在查询Hbase之前利用布隆过滤器过滤是一种不错的优化方式。布隆过滤器可以过滤掉一定不存在的数据,保留可能存在和一定存在的数据。这样可以减少对Hbase查询访问所消耗的时间。在我设计的系统中,例如全量数据查询某特定权限的问题,就是整体数据是否存在于小范围的数据中,使用布隆过滤器对于性能提升很有帮助。