HBase是Apache Hadoop的一个子项目,Google发表的GFS、MapReduce、BigTable三篇论文,号称“三驾马车”,开启了大数据时代,而Hbase则是来源于其中的bigtable,提出了一种分布式数据库的思想,旨在利用数千台廉价的Pc机,搭建一个可以处理PB级海量数据的数据存储服务。
HBase是bigtable的一个开源实现,提供了高可靠性,高性能,列存储,可伸缩,实时读写的非关系型数据库系统[3]。Hadoop生态圈如图1.1所示。
图1.1 Hadoop生态圈
在Hadoop生态圈中,HBase扮演了一个很重要的角色,它利用HDFS作为底层存储,MapReduce、Spark、Hive等,都可以依赖HBase作为数据源,或者将数据计算结果储存在HBase中。
一、数据存储结构
HBase与传统的关系型数据库不同,关系型数据库在提前设计数据库表结构的时候,需要确定每个字段的数据类型,每一行由固定的列组成,而HBase是一种NoSql数据库,利用key-value的方式,可以自由的在列族中添加列,而不需要修改表结构或者添加关联表,如图1.2和1.3所示。
图1.2 关系型数据库
图1.3 存储模型例图
可以看到HBase的存储结构是列式存储,每一行的列是不同的,而类似MySql这种数据库都是行式存储,列式存储相对比行式存储,它在查询数据的时候,可以只查询需要的列,存储的时候,也可以根据列来分区存储。
1
行键(row_key)
(1)row_key的设计对于HBase的使用来说,至关重要。作为NoSql数据库,HBase的row_key就是用来唯一指定一条数据的主键,我们想要从HBase检索一条数据,必须要依赖row_key,否则就要全表扫描。
(2)而且HBase的数据存储,主要也依赖row_key,它决定了一条数据存储在哪一个节点,以及在节点中的位置。
通过row_key获取数据实例:
其中:User代表表名,row代表row_key, info代表列族,sex代表列
get 'User', 'row', 'info:sex'
2
时间戳(timestamp)
(1)HBase利用时间戳的形式,实现了数据的修改和删除操作,在对数据进行编辑的时候,不会去直接修改原值,而是通过以时间戳为版本号,在原来的数据后面追加。
(2)时间戳默认是更新数据时的系统时间,也可以是客户端手动赋值,时间戳越大,则数据越新,不同时间戳的数据,按照时间戳的倒序排序,最新的一条在最前面。
(3)我们也可以利用时间戳来判断一条数据是否超时,例如我们可以设置列族的TTL时间,我们会依赖时间戳和设置的TTL时间来判断数据是否过期,如果过期则不会被查到。
(4)每一个列族的单元数据的版本数量都被 HBase 单独维护,默认情况下 HBase 保留 3 个版本数据。[1]
3
列族(column family)
(1)当在HBase新建一个表的时候,可以不定义列,但是需要定义好列族,然后在插入数据的时候,可以根据需求,动态新增列。
(2)列族中包含了多个列,查询数据的时候,需要指定列族,再指定列。
(3)HBase的存储是按照列族来分区存储。
4
单元格(cell)
由于一条数据可以有多个版本,所以row_kwy + column family + column + version才能确定一个单元的数据,这个单元的数据为单元格(cell)。
二、架构体系
Hbase的架构图如图1.4所示。
图1.4 HBase架构图
上图是一个很经典的HBase架构图,上面列举了HBase各个模块以及他们之间的关系,理解这个架构图,我们就能知道为什么HBase能成为实时读写的海量数据存储的数据库。
其中,主要的几个模块是:client、HMaster、HRegionServer。HMaster相当于HBase协调者,负责了整个HBase的协调工作:
(1)负责接收用户页面的请求,查看HBase集群信息,负责处理新建表,删除表的请求,处理Schema的更新等。负责管理HRegion服务器的负载均衡,重新分配等。
(2)HRegionServer是运行在每个节点上的服务,负责响应用户的I/O请求,从HDFS中读写数据。
(3)HRegionServer会根据row_key的分布,切分Hregion,将数据按照row_key均匀分布在Hregion上。
(4)每个HregionServer会负责管理一批Hregion,每个Hregion里管理了多个Hstore, Hstore里负责存储一个cloumn family的数据。
Zookeeper存储了当前被选举为master的HMaster信息:作为热备的HMaster信息,HRegion server的信息,以及存储元数据的HRegion server节点,其中存着row_key对应Region的位置。当客户端读取数据的时候,H会从元数据的信息判断去哪台机器上读写数据。
HDFS则负责存储HBase的所有数据,他来源于Google的另一篇论文GFS,是一个分布式文件存储系统,它可以利用廉价的Pc机存储海量数据,并且易扩展,高可用。
三、如何定位一条数据
在Hbase定位一条数据的流程如图1.5所示。
图1.5 如何定位一条数据
1
具体流程
(1)客户端Client首先连接Zookeeper上获取存储元信息的HRegion server节点,再从HRegion server获取到元数据,并缓存在本地的mata cache,根据元信息,client可以知道要查询的数据在哪个HRegion server上,以及它的ip、端口号。
(2)客户端获取到将要查询数据的HRegion server信息后,将数据读取请求发送到存有存有目标数据的HRegion server。
(3)HRegion server接收到数据请求后。
(4)查找对应的region,会先从memstore中查询(HBase在将数据写入store file之前,会先将数据写入memstore,当memstore的数据达到一定的阈值的时候,才会将数据刷入store file中)。
(5)如果查不到,会在Block cache中查询缓存(一个HRegion server只有一个Block cache,并且有LRU淘汰策略)。
(6)如果查不到,会从store file(HFile)中查询,并存入Block cache。
(7)将查到的数据返回client。
2
关于HBase数据分布
Hbase的数据是依赖row key按照字典顺序存储,刚开始的时候,一张表只有一个region,随着数据量的增长,HBase会将数据水平拆分,分别存在不同的region上,如图1.6所示。
图1.6 Hbase的数据分布
Region按照Row key水平拆分存储,每个Region中Row key 的start key和end key代表了它存储的按照字段顺序排序的最大Row key,和最小Row key,而当要按照一个Row key进行查询的时候,如果Row key在这个范围内,则这条数据必然会存在于这个Region中。
Region是HBase负载均衡的最小单元,当前Region的数据会随着当前Region数据量的达到预设的阈值,分裂成两个Region,可以利用Region的负载均衡机制,做预分区,以达到类似Mysql的分库分表效果。
所以Row key的设计至关重要,影响了数据的存储是否均衡,每一个读写请求是否高效。
3
设计Row key
唯一性:由于是Nosql数据库,类似我们常使用的Redis,一定要保证Key的唯一性,相同的Row key的数据将会被认为是一条数据。
利用递增性:由于HBase是按照Row key的字典顺序存储,分区,那我们可以利用这个特点,设计row key时,加入容易被range查询的字段作为后缀,比如时间戳。
写入优化[2]:如果我们的Row key是一个完全递增的字段,比如利用Mysql数据库的主键、一个全局递增的订单Id、甚至是一个时间戳,那么我们在写入数据的时候会写在单个region上,从而出现热点问题,所以需要将数据分散到多个region上。
散列:将原Row key散列后的值,作为新Row key存储,但是会有Hash碰撞的问题。
salting:可以在Row key前面加一个固定长度的随机数,或者是其他前缀,可以使数据的分配均衡分配。
四、使用场景以及和其他数据库对比
要知道HBase的使用场景,首先需要明确它的特点:
(1)海量存储:HBase可以存储PB级别的海量数据。
(2)易扩展:随着数据量的增大,可以通过添加HRegion server节点,水平扩展,而且HBase依赖的HDFS也是一个分布式存储系统,可以通过添加Data Node进行扩展。
(3)稀疏:HBase是列式存储,为空的列不会占用空间。
(4)高可靠性:数据存储利用HDFS,HDFS多个冗余节点保证了数据服务的高可用;WAL(Write Ahead Log)机制,数据写入memstore之前,会先将数据写入HLOG中,保证了某个Region出现问题后,数据不会丢失。
(5)高性能:利用Row key切分Region,以Row key为索引,能快速定位到一个Region,在一台HRegion server节点只存储了部分数据,并且通过缓存,能快速定位数据,可以达到毫秒级别。
(6)数据类型单一:HBase中全部使用文本存储。
(7)多版本:HBase的修改不会覆盖数据,而是以多个版本的形式增量存储,会保存之前版本的数据。
数据模式是动态的或者可变的,且支持半结构化和非结构化的数据[1]。数据库中的很多列都包含了很多空字段,利用了稀疏性,在 HBase 中的空字段不会像在关系型数据库中占用空间。需要很高的吞吐量,瞬间写入量很大。数据有很多版本需要维护,HBase 利用时间戳来区分不同版本的数据。需要具有高可扩展性,HBase能动态地扩展整个存储系统。
五、应用举例
原生应用如图1.7所示。
图1.7 原生应用图
时间维度列表:设计rowkey为uid+时间戳,比如GPS轨迹、Feed流、历史订单、朋友圈等。
例:用户的手机imei\手机号码等唯一信息加上上传时间组合:
123456_20180303
123456_20180204
123456_20180107
可以利用HBase按rowkey范围,查询到用户所有用户GPS轨迹:
[123456_000000,123456_99999999]
MR等分析任务的数据源离线分析,包括图形化展示、用户画像、差集交集并集统计,具体如下:
(1)业务线把交易记录实时同步到HBase表。
(2)定时任务对HBase表进行全表扫描,map、reduce 分析,生成结果信息存入存储。
(3)业务线从存储中获取统计结果。
六、和其他数据库对比
1
MySql
(1)MySql是单机存储,可以存的数据量很有限,而且数据量过大,会严重影响性能。
(2)MySql是关系型数据库,而HBase是NoSql数据库,列式存储。
(3)HBase不支持事务,而且不支持条件查询(可以利用ES等作为二级索引)。
2
Redis
(1)同为NoSql数据库,Redis的读写速度远超过HBase。
(2)Redis不能存储大数据量数据。
3
ES
(1)ES在写入的时候,需要构建倒排索引,分词等操作,相比HBase需要耗费更多的资源。
(2)HBase可以依靠合理的预分区,合理分配负载。
七、使用经验
1
司机轨迹查询
司机轨迹的查询如图1.8所示。
图1.8 司机轨迹
利用HBase,存储司机id、司机电话、司机GPS等信息,在地图上绘制司机运动轨迹,用来定位司机位置和问题排查。
Row key设计规则如下:
(1)hash(司机id)%10_${timestamp}。
(2)数据预分区10个,利用hash(司机id)%10,使数据均匀分布在各个节点。
(3)同一个司机的数据,在一个节点,并且按照时间排序。
(4)按照时间查询司机位置,并且在地图上绘制轨迹,时间控制在1s以内。
数据量日益增大,日均3G数据持续下去必将支撑不住,可以做如下优化:
(1)设置过期时限(利用时间戳版本的TTL)。
(2)引入冷存储作为历史数据的存储及查询(一般查询时间范围是最近一段时间)。
2
实时监控告警
实时监控告警如图1.9所示。
图1.9 实时监控告警
(1)使用SDK、Flume等方式,将业务数据发送到Kafka集群。
(2)使用Sparkstreaming实时分析,将数据计算结果按照业务key+时间戳作为Row key,存到HBase中。
(3)前端按照业务key+时间戳,范围查询并展示。
八、总结
(1)HBase利用HDFS作为数据存储,可以使用多台廉价的机器存储海量数据。
(2)HBase的一条数据数据是有一个Row key和列族,以及列族中的列和他对应的值组长。
(3)HBase是一个Nosql数据库,利用Row key可以快速定位一条数据。
(4)HBase的删除、修改数据都会保留版本。
(5)利用Row key的特性,可以方便我们将相近的数据存在一起,并按规律范围查询一些数据,并且可以避免数据的倾斜以及热点问题。
参考文献
[1]HBase数据库入门教程(http://c.biancheng.net/hbase/)
[2]翻译图书:作者Nick Dimiduk,Amandeep Khuranna. 书名《HBase实战》 版次 第一版.译者 谢磊. 出版地: 北京 出版者,出版年 2013年.
[3]HBase官方文档(https://www.w3cschool.cn/hbase_doc/)
[4]我终于看懂了HBase,太不容易了...(https://zhuanlan.zhihu.com/p/145551967?utm_source=wechat_session)
往期推荐
扫码关注我们
致力于互联网教育技术的创新和推广
@学而思网校技术团队