本文简单介绍了 HBase 的一些原理。

数据模型

介绍

数据被存在打标签的表中。每一个表格都被打了版本号,默认情况下,版本号是在表格被插入数据时间的时间戳。表格的内容是没被解析的字节数组

表的 row-key 也是字节数组。所以理论上任何数据结构都可以是 row-key。表的数据根据 row-key 来排序,所以可以认为 row-key 就是表的 主键。HBase 所有的数据都通过 row-key 获取,原生不支持二级索引。

每一行的每一列数据都被打包进一个 列族 中。每个列族中的成员都有一个相同的前缀。如上图所示

  • info
    info:format, info:geo

  • contents
    contents:image

列族的前缀必须是可打印的(printable),列名和前缀间用冒号分割。

表的列族必须在设计表的 schema 的时候就定义好,而每个列族增加新的成员则只需要在需要的时候添加。

在实体存储上,每个列族的所有成员都存储在文件系统的同一个地方。

由于性能调优和存储细节都是在列族级别进行的,所以: 列族的所有成员都有相同的存贮模式和大小

比如上图中的图片存储设计得就很合理: contents:image 存的是图片原始二进制数据(M 级别的大小),info 列族存的元信息是 K 级别的大小。

Regions

表被 HBase 自动分区到多个 Region。每个 region 都包含了这张表的一部分行数据

每张表都会标记 每个 region 包含的起始 row-key 和 结束 row-key。

最开始的时候每张表只有一个 region,随着每个 region 包含的数据量超过了某个设定的值,这个 region 被分割成两个包含几乎相同数据量的新的 region。

锁机制

行数据的更新都是原子的,事务机制不关心一行有多少列族。

实现

HBase 集群由主节点控制一组从节点。主节点负责最初的安装,分配 region 以及崩溃恢复等事情。

主节点的负载很小。

每个从节点都有 0 个或者多个 region 的数据,并且负责数据的读写。从节点还负责在数据量过大时分割 region。

HBase 依赖 ZooKeeper, ZK 会保留集群的重要信息,比如:hbase:meta 和集群主节点地址。

当分割 Region 的时候参与的节点崩溃的话分割会通过 ZK 来进行。

ZK 会保留分割 region 的事务状态,这使得在节点崩溃需要恢复状态的过程变得容易。

另外,当客户端在做请求路由时,也可以通过 ZK 来得到想要的 region 地址。

HBase 使用 HDFS API 来做数据持久化。

HBase 操作

在 HBase 中,用户层面的元数据保留在 hbase:meta 表。hbase:meta 中的每一条记录是以 region name 作为 row-key 的。其中,region name 是以 表名,起始行,创建时间和以上这些信息的 MD5 值组成的。如下所示:

TestTable,xyz,1279729913622.1b6e176fb8d8aa88fd4ab6bc80247ece.

每当这些信息有更新,这个表里的数据就会发生变化。当新的客户端连接到 ZK 集群时,首先去查看 hbase:meta 表,得到需要查找的 region 节点后,先缓存相关信息,以后直接连接这个 region 执行操作直到发生错误然后再从新找 hbase:meta。

到达某个 region 的所有写操作先追加到 commit-log 日志文件,然后加在内存中,直到内存数据大小大于某个值然后 flush 到 硬盘。

commit-log 放在 HDFS 上,所以即使 region 节点崩溃也是可以用的。