HBase理解

一.概述

在互联网应用中,经常需要存储大量的用户数据,然后对这些数据进行加工,分析最终产出对用户有价值的数据,关于数据的存储,我们可以选择文件,缓存以及数据库等,在数据库我们经常使用关系型数据库(mysql,oracle等)来存储,当数据达到一定量就需要进行分表分库,以便提高数据库的查询效率,例如在mysql中当表记录行数超过400万的时候,通常就需要分表。但是如果我们存储数据的时候选择的是HBase,这时候就不用分表,HBase中的表可以支撑上亿行,上百万列,这些数据最终存储都是分布在多台机器上的,因此HBase可以存储大量的数据,但是HBase就不具备关系型数据库的关联查询,就是说在HBase中不存在表和表的JOIN查询,关系型的查询是关系型数据库天生的优势,这样在HBase中存储的数据一定是一些弱关系的数据,要是数据之间有很强的关系,那就不太适合存储在HBase中了。

HBase中表的Schema很灵活,每行记录的列数都可能不一样,第m行的有x列,第n行有y列,不像关系型数据库,第m行和第n行必须有相同的列数。在定义HBase表Schema的时候,我们不需要指定这张表有多少列,列的增加和删除都是动态的。

关系型数据库数据的存储是面向行的,HBase数据的存储是面向列,在HBase中存储数据的时候都是以K/V的形式存储的,一行HBase的记录对应存储层的多条K/V的记录。

二.HBase相关概念


  • 和关系型数据库一样,存储数据到HBase的时候先要建立一张表
  • 列族
    HBase中每张表都是有1个或者多个列族组成的,每张表至少要有1个列族

  • 在关系型数据库中列是直接属于表的,但是在HBase中列是和列族关联在一起的,一个列族下面可以有多个列
  • rowkey
    在HBase中每行记录都和一个rowkey关联,这个rowkey决定了记录存储在什么地方,在获取记录的时候通常需要指定一个rowkey或者rowkey相关的数据,这样就能定位到在那台机器上获取数据了,在存储数据的时候,都是按照rowkey的字典序来存储的
  • timestamp
    在HBase中,每个列的数据可以存储多个版本,这个timestamp就是用来标识数据存储写入HBase时的时间戳
  • version
    HBase中每个列存储数据的时候,默认存储三个版本的数据,每个数据都有一个版本号,这个版本号可以让HBase自动来生成,也可以自己指定。
  • TTL
    time-to-live,HBase中列的数据都有一定的过期时间,当超过这个时间后,这个数据就会自动被HBase删除
  • cell
    HBase中数据存储的最小单元,这个单元包含了列名,列的值,时间戳,版本,列族以及rowkey

在HBase中,可以有多张表,每张表有多个列族,一个列族中可以有多个列,每个列可存储多个版本的数据。因此对于某张表某一列族下面的一行记录,我们可以抽象出这样的数据结构

SortedMap<RowKey,List<SortedMap<Column,List<Value,Timestamp>>>

注意:
1.存储的时候首先按照rowkey进行排序,一个rowkey会关联多个列,多个列存储的时候按照列名的字典序排列。
2.由于HBase中存储了多个版本的数据单元,因此HBase中就没有真正意义上的数据更新,所有的更新都是插入,超过数据单元的版本数目后,老的数据自动被剔除。

三.HBase数据存储理念

我们创建HBase表的时候,只要需要指定表名和列族即可,不用特意去指定某个特定的列族下面有多少列,如下图所示:
HBase建表

建完表后,我们可以使用describe命令来查看我们刚才所建立的表。前面我们已经说过HBase在数据存储的时候是面向列存储的,而mysql在存储数据的时候是按照行存储的。我们可以使用scan命令来查看表中的数据(自己完可以这么搞,但是线上千万别用scan乱来),如下图所示:
HBase数据存储

通过上图我们可以看到HBASE_PUT_ROW_KEY_A所在的行有4列数据,即COL_NAME_A,COL_NAME_B,COL_NAME_C,COL_NAME_D。HBASE_PUT_ROW_KEY_B所在的行有两列数据既COL_NAME_A,COL_NAME_D。HBASE_PUT_ROW_KEY_C所在的行有两列数据,即COL_NAME_B和COL_NAME_C。HBASE_PUT_ROW_KEY_D所在的行也有两列数据,既COL_NAME_B和COL_NAME_C,假如我们把这样的数据存储在mysql后会出现下面的存储视图:
HBase存储转换成mysql存储试图

这样的存储视图出现在mysql中会造成两个问题:

  • 上图已经很清楚描述了存储格局,明显出现有些数据单元被浪费掉了。
  • 要是在来一行数据,这行数据需要有五列,这时mysql表就满足不了,需要重新修改表结构才能满足这样的存储需求。

在HBase中存储是面向列进行存储的,因此上面的存储格局不会出现存储单元的浪费,同时HBase表的列是可以动态增加的,因此也不用担心多出四列的行没法存储的问题。其实可以这么说,正是由于HBase的存储理念是面向列的存储,才导致HBase中表schema非常灵活,列可以动态增加和删除。