前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HBase的数据结构原理与使用

HBase的数据结构原理与使用

原创
作者头像
凉粉
修改2023-06-28 01:26:21
2K0
修改2023-06-28 01:26:21
举报
文章被收录于专栏:凉粉凉粉

一、HBase简介

HBase是一个开源的、分布式的、版本化的NoSQL数据库(即非关系型数据库),依托Hadoop分布式文件系统HDFS提供分布式数据存储,利用MapReduce来处理海量数据,用Zookeeper作为其分布式协同服务,一般用于存储海量数据。HDFS和HBase的区别在于,HDFS是文件系统,而HBase是数据库。HBase只是一个NoSQL数据库,把数据存在HDFS上。可以把HBase当做是MySQL,把HDFS当做是硬盘。

二、HBase的数据结构

1、索引结构:LSM树

传统关系型数据普通索引采用B+树。B+树最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在磁盘存储上往往不连续,分离得很远,随机读写概率会变大,做范围查询时,会产生大量读随机IO。为了克服B+树的弱点,HBase引入了LSM树的概念,即Log-Structured Merge-Trees,直译为日志结构合并树。基于LSM树实现的HBase的写性能相比Mysql放弃部分磁盘读性能,换取写性能的大幅提升。

LSM树严格来说不是一个具体的数据结构,更多是一种数据结构的设计思想。LSM树不是一棵树,而是由至少两个存储结构构成。假设这两颗树分别为C0和C1,C0比较小,全部驻于内存之中,具体可以是任何方便健值查找的数据结构。而C1则驻于机械硬盘。一条新的记录先是从C0中插入,如果这一次的插入造成了C0数据量超出了阀值,那么C0中的部分些数据片段则会直接合并到C1树中。如果有多级树,当C1体量越来越大就向C2合并,低级的树在达到大小阈值后也会在磁盘中进行合并,以此类推,一直往上合并Ck。

LSM树的设计思想:

划分不同等级的树。将对数据的修改增量保持在内存中,数据更新只在内存中操作,没有磁盘访问。达到指定的大小限制后将这些修改操作批量写入磁盘。由于内存的读写速率都比磁盘要快非常多,因此数据写入内存的效率很高。随着小树越来越大,达到指定的阀值限制后将这些修改操作批量写入磁盘,磁盘中的树定期做多路归并操作,合并成一棵大树,以优化读性能。随机读写比顺序读写慢很多,为了提升IO性能,需要将随机操作变为顺序操作。LSM树使用日志文件和一个内存存储结构把随机写转化成顺序写,读写独立,数据从内存刷入磁盘时是预排序的,写性能大幅提升。读取的时候稍微麻烦,需要先看是否命中内存,如果读取的是最近访问过的数据则可以命中,否则需要访问较多的磁盘文件。

使用LSM树的数据库除了HBase,还有nessDB、levelDB、TiDB、RocksDB等。

(图中MongoDB只有WiredTiger(WT)存储引擎既支持B-树,又支持LSM树存储索引。)
(图中MongoDB只有WiredTiger(WT)存储引擎既支持B-树,又支持LSM树存储索引。)

2、存储结构

HBase的LSM树中存储的是多个Key-Value结构组成的集合,每一个Key-Value一般都会用一个字节数组来表示。这个字节数组串设计如图所示:

(图源:胡争,范欣欣《HBase原理与实践》第二章《基础数据结构与算法》)
(图源:胡争,范欣欣《HBase原理与实践》第二章《基础数据结构与算法》)

字节数组主要分为以下几个字段。其中Rowkey、Family、Qualifier、Timestamp、Type这5个字段组成KeyValue中的key部分。

• keyLen:用来存储KeyValue结构中Key所占用的字节长度。

• valueLen:用来存储KeyValue结构中Value所占用的字节长度。

• rowkeyLen:用来存储rowkey占用的字节长度。

• rowkeyBytes:用来存储rowkey的二进制内容。

• familyLen:用来存储Family占用的字节长度。

• familyBytes:用来存储Family的二进制内容。

• qualif ierBytes:用来存储Qualif ier的二进制内。注意,HBase并没有单独分配字节用来存储qualif ierLen,因为可以通过keyLen和其他字段的长度计算出qualif ierLen。

• timestamp:表示timestamp对应的long值。

• type:表示这个KeyValue操作的类型,HBase内有Put、Delete、Delete Column、DeleteFamily,等等。

HBase的LSM树在内存一般采用跳跃表存储,跳跃表的查找、删除、插入的复杂度都是O(logN)。

LSM树在磁盘中的数据结构也不是树结构,而是Key-Value结构组成的序列,称为SSTable(Sorted String Table)有序字符串表。当SSTable太大时,为了加快SSTable的读取,可以将其划分为多个块,通过记录每个块的起始位置,构建每个SSTable的稀疏索引。这样在读SSTable前,通过索引就知道要读取的数据块磁盘位置了。SSTable索引需要永远加载在内存里。写是写内存,因此随机写十分快。读也是读内存里的 SSTable的索引,并且这里每一个SSTable索引如果用二分法查找,算法复杂度大致在O(lg(n))与O(n)之间,因此随机读也不慢。

3、表结构

与传统的关系型数据库类似,HBase也以表的形式组织数据,表也由行和列组成,不同的是,HBase采用列式存储。

如上图所示的表,如果采用列式存储,会存成下图的结构:

可以发现,列式存储就是把每列抽出来,然后关联上ID,实际上是用Key-Value结构保存的。这样的优点在于,当表格中有空缺时,可以充分利用存储空间。

对HBase来说,一行数据由一个行键(RowKey)和一个或多个相关的列以及它的值所组成。列的组成都是灵活的,行与行之间的列不需要相同。行键(RowKey)就是SSTable的key。

在HBase里边,先有列族(也叫“列簇”,Column Family),后有列。列族将一列或者多列组织在一起,HBase的每一个列都必须属于某个列族。HBase的列都得归属到列族中,如图所示:

数据写到HBase的时候都会被记录一个时间戳,这个时间戳被我们当做一个版本。比如说,我们修改或者删除某一条的时候,本质上是往里边新增一条数据,记录的版本加一了而已。如图所示:

被更新和删除的数据不会直接从磁盘上删除,而是为数据添加一个删除标记,查找时会跳过被删除的键,DBA运维会定期删除被标记删除的数据。因此,如果存在频繁覆盖删除需要提前向运维报备以免影响数据库性能。

三、HBase的使用

1、HBase的读写

HBase提供了多种模式、多种语言的访问接口。目前常用的包括Native Java API,Thrift和MapReduce模式。

(1)Java API是HBase提供的原生接口,具备完善的客户端处理逻辑,直接与HBase Server进行通信,效率最高,但受限于语言限制;

(2)Thrift不受语言限制,但会占用额外的网络带宽和处理时间;

(3)HBase还支持了MapReduce,可以通过编写MapReduce任务进行批量数据操作。

使用GoLang和PHP语言搭建的项目显然得用Thrift接口。

常用的HBase的数据操作get、scan和put三种。

(1)get实现随机读取功能,根据指定RowKey获取惟一一条记录。

(2)scan提供批量查询功能,按照指定的条件获取一批记录。通过指定起始和中止的key,即可获取所有包含在内的key对应的数据。可以通过setStartRow与setEndRow来限定范围,也可以通过setFilter方法添加过滤器,这也是分页、多条件查询的基础,用setCaching和setBatch方法能提高速度。

(3)put实现写入,如果要批量导入大规模数据,还可以采用bulkimport的方式。

2、行键(RowKey)设计

Rowkey相当于HBase中数据的主键。HBase中的数据是按照RowKey的ASCII字典顺序进行全局排序。可以使相关行彼此靠近存储。如果Rowkey设计不当会引发热点问题,即客户端大量的读写请求都集中在一个或几个节点上。从而导致性能下降。为防止数据写入时出现热点,数据被写入时应写入集群中的多个区域,而不是一次写入一个区域(Hregion)。

设计原则:

1、唯一原则,要保证Rowkey的唯一性。若HBase中同一表插入相同Rowkey,则原先的数据会被覆盖掉。设计Rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

2、长度原则。Rowkey长度越短越好,一般不要超过16字节。因为RowKey是一个二进制码流,可以是任意字符串,最大长度64KB,实际应用中一般为10-100字节,以byte[]形式保存。如果RowKey过长比如500个字节,1000万列数据仅RowKey就要占用5GB空间,非常影响HFile的存储效率。

3、散列原则。用时间戳作为Rowkey的前缀会导致大量数据堆积在一个区域进而导致热点问题。如果Rowkey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将Rowkey的高位作为散列字段,低位放时间字段。

3、列族(Column Family)的设计

设计原则:

1、列族的名称尽可能短,甚至可以是一个字符。例如,“d”表示数据/默认值。

2、HBase当前不能很好地处理超过两个或三个列族的数据,因此请保持列族的数量较少。最好使用一个列族。仅在数据访问通常是列范围的情况下才引入第二和第三列族。即,一次只查询一个列族,通常不会查询两个列族。

3、将相同IO特性的列放入同一列族。

4、多个列族中的数据(行数)分布大致均匀。

5、对于临时性的列族可以设置失效时间。一旦达到到期时间,HBase将自动删除行。

4、HBase Shell的安装和使用

HBase自带的操作工具只有HBase Shell这一命令行终端。通过HBase Shell工具,可以交互式地进行数据管理,包括插入数据、删除数据等。虽然也有一些第三方图形界面客户端支持HBase,如DBeaver、BigInsights、HbaseGUI,但系统部的HBase只支持HBase Shell。

安装HBase Shell需要先挑选一台用于安装的虚拟机,为该虚拟机安装Java环境。之后在系统部奇麟大数据的客户端管理页面选择“添加客户端账号”,申请为该虚拟机添加项目账号。申请通过后勾选机器,单击“部署Hadoop环境”在该机器上安装HBase Shell。

安装成功后,到虚拟机上使用sudo -iu命令先切换到项目账号。然后切换到目录cd $HBASE_HOME/bin,运行hbase shell,即可进入HBase Shell程序。

这里列出几个常用的HBase Shell命令:

名称

命令表达式

查看存在哪些表

list

添加数据

put '表名称', '行键', '列族 : 列名', '值'

查看一行数据

get '表名称', '行键'

查看指定列族的一行数据

get '表名称', '行键', '列族'

查看指定列族及列名的数据

get '表名称', '行键', '列族 : 列名', 

查看表中的数据总量

count '表名'

删除一个单元格的数据

delete '表名' ,'行键' , '列族 : 列名'

删除一行所有数据

delete '表名' ,'行键'

查看表的所有数据

scan '表名'。注意,一般不应直接使用scan扫描整个表的海量数据。

查看一列数据

scan '表名' , '列族 : 列名'

查看帮助信息

help

5、MongoDB数据迁移HBase

使用kettle等工具可以把MongoDB数据库迁移到HBase。也可以使用MapReduce处理,速度远快于Java API和Thrift。

参考文献:

胡争,范欣欣.HBase原理与实践M.北京:机械工业出版社,2019

O’Neil, P., Cheng, E., Gawlick, D., & O’Neil, E. (1996). The log-structured merge-tree (LSM-tree). Acta Informatica, 33(4), 351-385.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、HBase简介
  • 二、HBase的数据结构
    • 1、索引结构:LSM树
      • 2、存储结构
        • 3、表结构
        • 三、HBase的使用
          • 1、HBase的读写
            • 2、行键(RowKey)设计
              • 3、列族(Column Family)的设计
                • 4、HBase Shell的安装和使用
                  • 5、MongoDB数据迁移HBase
                  相关产品与服务
                  数据库
                  云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档