分布式数据库HBase:从零开始了解列式存储-数据模型

时间:2024-07-05 10:44:53

数据模型是一个数据库产品的核心, 接下来将介绍HBase列族数据模型并阐述HBase数据库的概念视图和物理视图的差异.

相关概念

HBase实际上是一个稀疏、多维、持久化存储的映射表, 采用行键、列族、列限定符和时间戳进行索引, 每个值都是未经解释的字节数组byte[].

表由行和列组成, 列被分为若干个列族

每个HBase表都由若干行组成, 每个行由行键(Row Key)进行标识.

访问表中的行有3种方式:

  1. 通过单个行键访问
  2. 通过行键区间访问
  3. 全表扫描

行键可以是任意字符串(最大长度64KB, 实际应用中一般为10-100字节). 在HBase内部将行键保存为 字节数组, 按照行键的 字典序 排序. 所以在设计行键时可以充分考虑该特性, 将需要一起读的行存储在一起.

列族

HBase中一个表被分为多个列族, 列族是最基本的访问控制单元. 表中的每个列都必须属于一个列族, 我们可以将其理解为 把列按照需求分到不同的组中, 就如同整理文件到不同的文件夹中去.

为什么要这么做?

  1. 控制权限. 我们通过列族可以实现权限的控制, 例如某些应用只可以修改某些数据.
  2. 获得更高的压缩率. 同一个列族中的所有数据都属于同一种数据类型, 着通常意味着更高的压缩率.

缺点

  1. 列族数量不可太多. HBase的一些缺陷导致列族只能有几十个.
  2. 不能频繁修改.
列限定符

列族中的数据是通过列限定符来定位的. 列限定符无需事先定义, 也没有数据类型, 总被视为字节数组byte[].

单元格

在HBase的表中, 通过行、列和列限定符可以确定一个"单元格(Cell)". 单元格中存储的数据没有数据类型, 总被视为字节数组byte[].

每个单元格中可以保留一个数据的多个版本, 每个版本对应一个不同的时间戳.

时间戳

每个单元格都保留了同一个数据的多个版本, 这些版本采用时间戳进行索引. 事实上每一次对于一个单元格执行的操作(增删改)时, HBase都会自动生成并存储一个时间戳, 通常这个时间戳是64位整型. 当然, 这个时间戳也可以由用户自己赋值, 用以避免应用程序中出现数据版本冲突.

一个单元格中的不同版本的数据是以时间戳降序排序的, 以便于读到最新的数据版本.

我认为下面的一张图可以很好地表述上面的5个概念. 类比于关系数据库, 行键就是主键行号, 列限定符就是列名, 列族就是列名组成小组的组名, 单元格就是具体存储数据的格子, 时间戳则标识了一个单元格中不同时间的数据版本.

请添加图片描述

一个HBase数据模型的实例

数据坐标

相较于我们所熟悉的关系数据库, HBase无法仅使用行号和列号确定一个数据. 在HBase中, 我们需要: 行键、列族、列限定符和时间戳 这4个东西来确定一个数据.

[行键, 列族, 列限定符, 时间戳]被称为是HBase的坐标, 可以通过这个坐标来直接访问数据. 在这种层面上讲, HBase也可以被视为一个键值数据库.

概念视图

在HBase的概念视图中, 一个表是一个稀疏、多维的映射关系.

时间戳 列族 contents 列族 anchor
com.cnn.www t5 anchor:cnnsi.com="CNN"
t4 anchor:my.look.ca="CNN.com"
com.cnn.www t3 contents:html="xxxx"
t2 contents:html="xxxx"
t1 contents:html="xxxx"

上表存储了一个网页的页面内容(html代码)和一些反向连接. contents中存储的是网页内容, anchor中存储的是反向连接. 不过有几个地方需要额外注意:

  1. 行键. 行键采用的是url的倒序, 因为HBase的行键采用字典倒序排列, 这样可以使得相同的网页都保存在相邻的位置
  2. 每个行都包含了相同的列族, 即便有些列族不需要存储数据(为空)

物理视图

列族 contents

时间戳 列族 contents
com.cnn.www t3 contents:html="xxxx"
t2 contents:html="xxxx"
t1 contents:html="xxxx"

列族 anchor

时间戳 列族 anchor
com.cnn.www t5 anchor:cnnsi.com="CNN"
t4 anchor:my.look.ca="CNN.com"

我们可以轻易发现, 在物理的存储层面上来看HBase采用了基于列的存储方式, 而不是传统关系数据库那样基于行来存储. 这也是HBase与传统关系数据库间的重要区别.

与概念视图的不同

  1. 列族的分开存放. 可以看到contents和anchor两个列族被分开存放.
  2. 不存在空值. 在概念视图中有些列是空的, 但是在物理视图中这些值根本不会被存储.

总结

行式数据库使用 NSM(N-ary Storage Model) 存储模型, 将一个元组(或行)连续地存储在磁盘页中. 数据被一行一行地储存, 写完第一行再写第二行. 在读取数据时需要从磁盘中顺序扫描每个元组的完整内容. 显然, 如果每个元组只有少量属性的值对查询有用时, NSM模型会浪费许多磁盘空间.

列式数据库采用 DSM(Decomposition Storage Model) 存储模型, 将关系进行垂直分解, 以列为单位存储, 每个列单独存储. 该方法最小化了无用的I/O.

行式存储主要适合于小批量的数据处理, 比如联机事务处理. 列式数据库主要适用于批量数据处理和即席查询(Ad-Hoc Query). 列式数据库的优点是: 降低I/O开销, 支持大量用户并发查询, 数据处理速度比传统方法快100倍, 并且具有更高的数据压缩比.

如果严格从关系数据库的角度来看, HBase并不是一个列式存储的数据库, 毕竟它是以列族为单位进行分解的, 而不是每个列都单独存储. 但是HBase借鉴和利用了磁盘上这种列存的格式, 所以某种角度上来说它可以被视为列式数据库. 常用的商业化列式数据库有: Sybase IQ, Verticad等.

如果想要更深入地了解HBase的实现原理, 架构以及运行机制, 可以阅读我的博客: 分布式数据库HBase