浅谈HBase

2019-12-03 16:15:08 浏览数 (1)

数据的价值已经超越了传统企业广泛认同的价值边界,海量数据的存储将是企业所面临的的挑战。HBase正是这种背景下的产物,用以存储海量数据的,支持高并发、高性能、高可用、可伸缩、列存储等特性”

01

概述

在OLTP场景下,MySQL、Oracle等RMDBS已经不太适合作为海量数据的存储系统,它们更关注的是OLAP,也就是事务,根据CAP理论,MySQL等数据库为了实现事务(强一致性),使可用性和扩展性都受到了限制。也就是说,RMDBS并不适合作为海量数据的分布式存储场景来使用了。

2006年Google发表的论文“BigTable:A Distributed Storage System for Structured Data”,基于这个理论,HBase实现了BigTable存储架构。HBase是一个基于Hadoop和HDFS之上的分布式数据存储系统,它的优点是可以实现高性能的并发读写,数据可以进行透明的切分,支持水平扩展等。

02

架构

HBase是列式存储的(MySQL是行式存储),列式存储是按照列来划分的,这样使数据更加稀疏,当某行的列数据为空时,不会占有存储空间,更加节省空间。而且同一列上的数据格式都一致,压缩效率更高。

表结构

  • rowkey:表的主键,表中的数据按照rowkey字典序排列,类似于MySQL的主键ID;
  • 列族:列族是表的schema的一部分(而列不是),即建表时至少指定一个列族,表中的每个列都归属于某个列族;
  • 列:列肯定是表的某一列族下的一个列,用列族名:列名表示,相当于MySQL中具体的列;
  • 单元格:指定rowkey、列族、列,可以确定一个cell,即单元格,cell中的数据没有类型,是以字节数组进行存储的;
  • 时间戳:可以对表中的cell多次赋值,每次赋值操作时的时间戳,可以看出是cell的版本号,也就是一个cell可以有多个版本的值;

架构

  • 客户端:Client是操作HBase的入口,对于管理表的操作,如表的增、删、改操作,Client通过RPC与HMaster通信完成;对于表数据的读取操作,Client通过RPC与RegionServer交互,完成读取;
  • Zookeeper集群:
    • 实现了HMaster的高可用,多HMaster间进行主备选举;
    • 保存了HBase的元数据信息meta表,提供了HBase表中region的寻址入口的线索数据;
    • 对HMaster和HRegionServer实现了监控;
  • HMaster:
    • HBase集群也是主从架构,HMaster是主的角色
    • 主要负责Table表和Region的相关管理工作
      • 负责新的Region分配到指定的HRegionServer
      • 管理HRegionServer的负载均衡
      • HRegionServer宕机,负责其上面的Region的迁移
  • HRegionServer
    • HBase集群中从的角色,包含多个Region
    • 响应客户端的读写数据请求
  • Region
    • HBase集群中分布式存储的最小单元
    • 一个Region对应一个Table表的部分数据
    • Region包括具体的StoreFile,StoreFile存储在HDFS集群上

读写流程

读:

  • Client 与 Zookeeper集群通信,获取meta信息,并且找到对应表的regionserver地址和存储数据的region信息
  • Client 与 对应的HRegionServer进行通信,确定对应的region
  • 先查询region的memstore,看是否有要查询的数据,找到则返回,没有找到则进入下一步;
  • 再查询blockCache中,是否有要查询的数据,找到则返回,没有找到则进入下一步;
  • 缓存中没有找到数据的话,只能进行磁盘读取,从对应的HFile中读取对应的数据,返回给客户端。

写:

  • Client 与 Zookeeper集群通信,获取meta信息,并且找到对应表的regionserver地址和存储数据的region信息
  • Client 与 对应的HRegionServer进行通信,确定对应的region
  • 先把数据预写到HLog中,再写入memstore中;
  • flush阶段:memstore达到阈值,将memstore中的数据,刷到storeFile(HFile);
  • compact阶段:经过小合并、大合并,使每个region存储的信息更加紧密,提升查询效率;
  • split阶段:当每个region过大,反而不利于数据的查询,此时对达到阈值的region进行切分,提升查询效率;

compact分为小合并和大合并:

小合并:当memstore进行flush时,产生的storeFile,达到某个阈值时,需要进行的合并;

大合并:定时,对某个region下的所有storeFile进行一次合并;

通过合并可以减少region中HFile数量,使数据更加紧凑,提升查询效率;在大合并过程中,会进行清除过期、多余版本的数据;

03

预分区

当一个table刚被创建的时候,Hbase默认的分配一个region给table。也就是说这个时候,所有的读写请求都会访问到同一个regionServer的同一个region中,这个时候就达不到负载均衡的效果了,集群中的其他regionServer就可能会处于比较空闲的状态。解决这个问题可以用预分区,在创建table的时候就配置好,生成多个region。

增加预分区的好处:

  • 增加数据读写效率;
  • 负载均衡,防止数据倾斜;
  • 方便集群容灾调度region;
  • 优化Map数量;

每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。我们可以根据业务场景,设定每个表的分区边界,可以保证表中数据分布均匀,更贴近实际业务产生的数据特点。常用方式有手动指定分区和HexStringSplit 算法。

04

HBase版本确界和TTL

在HBase中,我们可以设置数据的历史版本保留个数,通过自定义历史版本保存的数量,可以查看多个历史版本的数据:

最大版本数:默认为1,表示每个列要保留的最大行版本数。通常,我们不要设置过大,以免增加HBase的维护成本。

最低版本数:默认为0,表示每个列要保留的最小行版本数,和TTL(生存时间,Time To Live)相结合使用。

在实际工作中,我们总会遇到某些数据过了一段时间就失效了。在HBase里,我们可以通过设置TTL来让这种数据过期清除掉

其实,HBase在处理数据的删除时,本质上为数据添加了一个墓碑标记,而数据仍然存在。我们已经知道的,在HBase进行大合并过程中,会删除掉多余的版本数据,这里面的依据就是在最大、最低版本数和过期时间的约束条件。

05

HBase的命名空间

在HBase中,namespace命名空间是指对一组表的逻辑分组,类似于RDBMS的数据库,方便对表在业务上的划分,这种抽象也为多用户的场景奠定了基础。HBase全局管理员能够创建、改动和回收namespace的授权。通常我们使用namespace包括配置管理、命名空间安全管理、Region服务器组等。

  • 配额管理:限制一个namespace可以使用的资源,包括region和table
  • 命名空间安全管理:提供了另一个层面的多租户安全管理
  • Region服务器组:一个命名或一张表,可以被固定到一组RegionServers上,从而保证了数据隔离性

可以创建,删除或更改名称空间。命名空间成员资格是在表创建期间通过指定以下格式的标准表名来确定的:

代码语言:javascript复制
<table namespace>:<table qualifier>
代码语言:javascript复制
创建namespace
hbase>create_namespace 'nametest'

查看namespace
hbase>describe_namespace 'nametest'

列出所有namespace
hbase>list_namespace

在namespace下创建表
hbase>create 'nametest:testtable', 'fm1'

查看namespace下的表
hbase>list_namespace_tables 'nametest'

删除namespace
hbase>drop_namespace 'nametest'

有两个预定义的命名空间:

  • hbase:系统命名空间,包含HBase的元数据表
  • default:默认命名空间,没有显示指定命名空间的表将会自动放入默认命名空间

06

Rowkey设计

HBase中的表的数据分割主要使用的列族而不是列,这和一般的列式存储数据库有所不同。每一行的单元格(Cell)被有序存储,同一列族的单元格被存储在一个存储文件(StoreFile)中,不同列族的单元格不会出现在同一个存储文件中。同一个单元格的多个版本被单独的存储为连续的单元格,而且按照时间戳降序排列,所以在读取数据时,最新的值先被读取到。每个单元格的结构为一个keyvalue,如下:

HBase的Region中的数据是“以行为粒度”划分的,而每个Region中的包含行的范围,即起始和结尾行。所以HBase的数据分布是否均匀,与rowkey的设计有直接关系。一个“好”的数据分布,应该是每个region数据量大小相近,访问量也接近。这样,数据可以均匀的分布在整个集群中,从而得到最后的资源利用率和负载均衡。当然这需要结合具体的业务场景来进行rowkey的设计,下面总结几点原则:

长度原则:rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中一般为10-100bytes,以byte[]形式保存,一般设计成定长。

散列原则:建议将rowkey的高位作为散列字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息。所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率。

通常使用的散列方法,如下:

1、预分区

预分区的目的让表的数据可以均衡的分散在集群中,而不是默认只有一个region分布在集群的一个节点上。

2、加盐

这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。

3、哈希

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据。

4、反转

反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。

唯一原则:必须在设计上保证其唯一性,rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,可以将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。


1、http://hbase.apache.org/book.html

2、《HBase权威指南》

0 人点赞