HBase 的行、列模型

在 HBase 中,数据存储在由行列构成的二维表中。在关系数据库(RDBMS)中,我们也有表的行,列概念。把hbase和Mysql之类的关系型数据库中的概念等价起来,是不对的,不利于理解Hbase的数据模型。

所以,这里的行和列千万不要理解为关系型数据库中的行、列概念。在学习Hbase之前,如果你没有学习过Mysql之类的关系型数据库,那么恭喜你,直接学习Hbase会更容易理解。


HBase 数据模型术语

Hbase中有很多Mysql中没有的概念,我们一起来学习一下吧。

我们先来看看一个图:

Hbase数据模型架构

结合这张图中出现的概念,我们进一步做一些解释。


HBase 表由多行组成。


HBase 中的一行由一个行键和一个或多个列组成。

在行存储时,顺序按照字母进行排序。因此,行键的设计非常重要。其目标是以相关行彼此靠近的方式存储数据。

常见的行键模式是网站域名。如果您的行键是域名,则应该反向存储它们(org.apache.www,org.apache.mail,org.apache.jira)。这样,所有 Apache 域名都在表中彼此靠近,而不是基于子域名的第一个字母展开。

这是一个比较好的技巧,一定要记住哦。在关系型数据库中,设计主键的时候,肯和这个相反,希望主键尽可能不一样,从而加速查询速度,但是在hbase中,不存在这个问题。


HBase 中的列由 列族列限定符组成,它们由:(冒号)字符分隔。

如:

content:pdf

content是列族,pdf是列限定符。

列族

出于性能原因,列族通常在物理上拥有一簇列及其值。每个列族都有一组存储属性,例如是否应将其值缓存在内存中,如何压缩其数据或对其行键进行编码等。表中的每一行都具有相同的列族,但是列族中存放的信息可能为空。

列限定符

列限定符被添加到列族中,以提供给定数据段的索引。给定列族content,列限定符可能是content:html,另一个可能是content:pdf。虽然列族在创建表时是固定的,但列限定符是可变的,并且行之间可能有很大差异。


单元格

单元格是行,列族和列限定符的组合,它包含一个值和一个时间戳,时间戳表示值的版本。

单元格可以指定一个特定的数据。


时间戳

时间戳与每个值一起写入,它是该值给定版本的标识符。默认情况下,时间戳表示写入数据时 RegionServer 上的时间。当您将数据放入单元格时,可以指定不同的时间戳值。


Hbase逻辑视图

我们来看看Hbase的的逻辑结构:

以下示例是一个Hbase的逻辑结构。我们有一个名为webtable的表,包含两行(com.cnn.wwwcom.example.www)和三个列族,名为contentsanchorpeople。在此示例中,对于第一行(com.cnn.www),anchor包含两列(anchor:cssnsi.comanchor:my.look.ca),contents包含一列(contents:html)。

此示例包含具有行键com.cnn.www的行的 5 个版本,以及具有行键com.example.www的行的一个版本。 contents:html列限定符包含给定网站的整个HTML。 anchor列族的限定符每个都包含指向该行所代表的站点的外部站点的链接,以及它在其链接的anchor中使用的文本。 people列系列表示与该站点关联的人员。

列名

按照惯例,列名由其列族前缀和*限定符*组成。例如,列 contents:html 由列族contentshtml限定符组成。冒号字符(:)从列族,限定符中分隔列族。

webtable

行键 时间戳 ColumnFamily contents ColumnFamily anchor ColumnFamily people
“com.cnn.www” T9 anchor:cnnsi.com = "CNN"
"com.cnn.www" T8 anchor:my.look.ca = "CNN.com"
"com.cnn.www" T6 contents:html = "<html>…"
"com.cnn.www" T5 contents:html = "<html>…"
"com.cnn.www" T3 contents:html = "<html>…"
“com.example.www” t5 contents:html = "<html>…" people:author = "John Doe"

此表中看起来为空的单元格在 HBase 中不占用空间,或实际上不存在。这和关系型数据库有明显的区别,关系型数据库中无论存没有存数据,都会占用空间,这也是HBase“稀疏”的原因。

表格视图不是查看 HBase 中数据的唯一方法,甚至也不是最准确的方法。以下表示与多维映射相同的信息。这只是一个出于演示目的的模型,可能并不完全准确。

我们用Json格式来表示Hbase的结构,会更合适。

{
  "com.cnn.www": {
    contents: {
      t6: contents:html: "<html>..."
      t5: contents:html: "<html>..."
      t3: contents:html: "<html>..."
    }
    anchor: {
      t9: anchor:cnnsi.com = "CNN"
      t8: anchor:my.look.ca = "CNN.com"
    }
    people: {}
  }
  "com.example.www": {
    contents: {
      t5: contents:html: "<html>..."
    }
    anchor: {}
    people: {
      t5: people:author: "John Doe"
    }
  }
} 

用json来表示是Hbase更为准备,它就像一个Key-Value映射,将Hbase理解为字典表会更合适。


Hbase物理视图(存储结构)

虽然在概念级别,表可以看作一组稀疏的行,但在物理意义上它们是按照列族存储的。可以随时将新的列限定符(column_family:column_qualifier)添加到现有列族中。

ColumnFamily webtable

Row Key Time Stamp 列族anchor
"com.cnn.www" t9 anchor:cnnsi.com = "CNN"
"com.cnn.www" t8 anchor:my.look.ca = "CNN.com"

ColumnFamily contents

Row Key Time Stamp ColumnFamily contents:
"com.cnn.www" t6 contents:html = "…​"
"com.cnn.www" t5 contents:html = "…​"
"com.cnn.www" t3 contents:html = "…​"

逻辑视图中显示的空单元格不占据物理存储空间。因此,对时间戳t8处对contents:html列的值的请求将不返回任何值,因为它没有被存储。

类似地,在时间戳t9处对anchor:my.look.ca值的请求将不返回任何值。但是,如果未提供时间戳,则将返回特定列的 最新值。给定多个版本,最新版本也是第一个版本, 因为时间戳按降序存储

因此,如果没有指定时间戳,则对行com.cnn.www中所有列的值的请求将是:来自时间戳t6contents:html的值,来自时间戳t9anchor:cnnsi.com的值,来自时间戳t8anchor:my.look.ca。理解本段的意思非常重要,每一个列中的值都是取版本最新的值。