HBase 的数据模型

1、HBse表结构

HBase 是面向列的数据库。有别于RDBMS(行式数据库),HBase将原来每一列中的数据放到一起进行存储。

RDBMS表结构(行式):
HBase 的数据模型
RDBMS中,每个行都是不可分割的,也就是说三个列username、age、sex 必须在一起,而且要
被存储在同一台机器上,甚至是同一个文件里面。

HBase 表结构(列式):
HBase 的数据模型
可以看到, RowKey 中 rk_id 这一行存储的,其实就是上一张表中对应的 id 这一列中的所有数据。也就是说,把第一张表每一列的数据值分别放到一起存储,就得到了这张表的表结构。
显然,在HBase中,每个行都是离散的。

这就是面向列的存储。

这种结构的好处是什么呢?

假如我们现在用的是关系型数据库RDBMS,我们要去存一个数据,这时候先要建立表结构,可能还要引入相关的索引,多表之间很有可能存在关联,如果当数据量比较大的时候,这时候查询上基本是很慢的。

而列式存储,每一列都是单独存放的,而且每一列的数据类型基本上是统一的(这是当然的,你能说 username 中含有 sex 属性的数据值吗?),这样的话,当你的表字段很多的时候,甚至可以把其中几个字段放在集群的一部分机器上,而另外几个字段放到另外一部分机器上,充分分散了负载压力。

2、HBase 与 HDFS 的关系

  • HBase 的存储是基于 Hadoop 的。Hadoop 实现了一个分布式文件系统 HDFS,HDFS 有高容错性的特点,并且提供高吞吐量以访问应用程序的数据,非常适合有超大数据集的数据。基于 Hadoop 意味着 HBase 能拥有同样强大的扩展性和吞吐量。
  • HBase 提供对数据的随即实时 读 / 写 访问能力。
  • HBase 内部使用哈希表,并存储索引,可将在 HDFS 文件中的数据进行快速查找。

3、HBase 使用选择

  • 主要需求是数据分析,比如做报表(数据分析是HBase的弱项)
  • 单表数据量不超过千万
  • 有 join,多级索引,表关系复杂的数据模型时

不要使用HBase,使用MySQL之类已足够(对于HBase或是其他 NoSql 来说,基本上都是不支持表关联的)

  • 瞬间写入量很大,单表数据量超千万,且并发很高
  • 数据需要长久保存,且量会持久增长到比较大的场景
  • HBase 不适用与有 join,多级索引,表关系复杂的数据模型

可以考虑使用 HBase。

4、HBase 数据存储模型

4.1 CAP 定理

  • Consistency(一致性):所有节点在同一时间具有相同的数据
  • Availability(可用性):保证每个请求不管成功或者失败都有响应,但不保证获取的数据为正确的数据
  • Partition tolerance(分区容错性):系统中个任意信息的丢失或失败不会影响系统的继续运作,系统如果不能再某一个时限内达成数据一致性,就必须在上面两个操作之间做出选择

对于分布式数据系统,分区容错是其最基本的要求,否则就无所谓“分布式”了,因此只能在一致性和可用性上做取舍。大多数情况下,都是牺牲一致性来换取可用性。

4.2 ACID

数据库事物正确执行有四个基本要素:

  • 原子性:一个事物要么全部执行,要么全部不执行,如果执行过程中发生了错误,系统就会回滚到最初的状态
  • 一致性:事物的运行不会改变数据库中数据的完整性。比如有 3 个银行账户,它们的总额加起来是 600 rmb,不同的账户之间同时发生多个转账,无论有多少个并发,即使发生宕机故障了,转完后,总额加起来依然会是 600 rmb。
  • 隔离性:两个以上的事物在执行的过程中,不会出现交错执行的状态(这样可能会导致数据的不一致)
  • 持久性:事物执行成功后,该事物对数据库的更改会持久的保存到数据库当中

HBase 作为一个 NoSql 数据库,并不支持严格的 ACID,它只支持到单个的行。

4.3 数据模型

  • NameSpace:命名空间
    • 相当于 RDBMS 的“数据库”。
    • 一个 namespace 包含一系列的表。
    • 当想把多个表分到一个组去统一管理的时候才会用到表命名空间。
    • 当数据库中没有那么多表的时候也用不到 namespace。
  • Table:
    • 一个表由一个或者多个列族组成。
    • 由于 HBase 中的表最终映射成 HDFS 上的文件,表名必须是能用在文件路径里的合法名字。
  • Row:
    • 每一行代表一个数据对象。
    • 每一行包含多个列,这些列通过列族来分类。
    • 每一行都是以一个行键(Row Key) 来进行唯一标识的,行键并没有什么特定的数据类型,以二进制的字节来存储。
    • RowKey 可以唯一标识一行记录,不可被改变。改变的唯一方式是删除这个 RowKey, 然后再插入。
    • 一行中的数据可以分布在不同的服务器上。

HBase 中的列由 列族(Column family)列(Column qualifier) 组成

  • Column Family:列族
    • 列族是多个列的集合。建表时定义的不是列,而是列族。
    • HBase 会尽量把同一个列族的列放到同一个服务器上,这样可以提高存取性能,并且可以批量管理有关联的一堆列。
    • 在物理上,一个 Column Family 的成员(多个列)在文件系统上是存储在一起的,存储和优化都是针对 Column Family 级别的,这就意味着,一个 Column Family 的所有成员都是用相同的方式访问的。因此,在定义 HBase 表的时候需要提前设置好列族,表中所有的列都需要组织在列族里面。列族一旦确定后,就不能轻易更改,因为它会影响到 HBase 真实的物理存储结构。
  • Column Qualifier:列(标识)
    • 多个 Column Qualifier 组成一行。 Column Qualifier 可以随意定义。
    • 列族中的数据通过列标识来进行映射,可以理解为一个键值对, Column Qualifier 就是 Key。
    • 可以认为 Column Qualifier 就是具体的列名。
    • 列族和列经常用Column Family: Column Qualifier 来一起表示
  • Cell:单元格
    • 一个列中可以存储多个版本的数据。而每个版本就称为一个单元格
    • 每一个行键,列族和列标识共同组成一个单元
  • Timestamp:时间戳 / 版本号
    • 默认 HBase 中数据插入时都会有一个 timestamp ,作为该值特定版本的标识符。
    • 读取数据时,如果时间戳没有被指定,则默认返回最新的数据;
    • 写入数据时,如果没有设置时间戳,默认使用当前的时间。
    • 每一个 列族 数据的版本都由 HBase 单独维护,默认的情况下,HBase 会保留 3 个 版本的数据
      HBase 的数据模型
      HBase 的数据模型

4.4 HBase 与 RDBMS 的区别

HBase 的数据模型