HBase 系列(二)—— HBase 系统架构及数据结构
一、基本概念
一个典型的 hbase table 表如下:
1.1 row key (行键)
row key
是用来检索记录的主键。想要访问 hbase table 中的数据,只有以下三种方式:
通过指定的
row key
进行访问;通过 row key 的 range 进行访问,即访问指定范围内的行;
进行全表扫描。
row key
可以是任意字符串,存储时数据按照 row key
的字典序进行排序。这里需要注意以下两点:
因为字典序对 int 排序的结果是 1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。如果你使用整型的字符串作为行键,那么为了保持整型的自然序,行键必须用 0 作左填充。
行的一次读写操作时原子性的 (不论一次读写多少列)。
1.2 column family(列族)
hbase 表中的每个列,都归属于某个列族。列族是表的 schema 的一部分,所以列族需要在创建表时进行定义。列族的所有列都以列族名作为前缀,例如 courses:history
,courses:math
都属于 courses
这个列族。
1.3 column qualifier (列限定符)
列限定符,你可以理解为是具体的列名,例如 courses:history
,courses:math
都属于 courses
这个列族,它们的列限定符分别是 history
和 math
。需要注意的是列限定符不是表 schema 的一部分,你可以在插入数据的过程中动态创建列。
1.4 column(列)
hbase 中的列由列族和列限定符组成,它们由 :
(冒号) 进行分隔,即一个完整的列名应该表述为 列族名 :列限定符
。
1.5 cell
cell
是行,列族和列限定符的组合,并包含值和时间戳。你可以等价理解为关系型数据库中由指定行和指定列确定的一个单元格,但不同的是 hbase 中的一个单元格是由多个版本的数据组成的,每个版本的数据用时间戳进行区分。
1.6 timestamp(时间戳)
hbase 中通过 row key
和 column
确定的为一个存储单元称为 cell
。每个 cell
都保存着同一份数据的多个版本。版本通过时间戳来索引,时间戳的类型是 64 位整型,时间戳可以由 hbase 在数据写入时自动赋值,也可以由客户显式指定。每个 cell
中,不同版本的数据按照时间戳倒序排列,即最新的数据排在最前面。
二、存储结构
2.1 regions
hbase table 中的所有行按照 row key
的字典序排列。hbase tables 通过行键的范围 (row key range) 被水平切分成多个 region
, 一个 region
包含了在 start key 和 end key 之间的所有行。
每个表一开始只有一个 region
,随着数据不断增加,region
会不断增大,当增大到一个阀值的时候,region
就会等分为两个新的 region
。当 table 中的行不断增多,就会有越来越多的 region
。
region
是 hbase 中分布式存储和负载均衡的最小单元。这意味着不同的 region
可以分布在不同的 region server
上。但一个 region
是不会拆分到多个 server 上的。
2.2 region server
region server
运行在 hdfs 的 datanode 上。它具有以下组件:
- wal(write ahead log,预写日志):用于存储尚未进持久化存储的数据记录,以便在发生故障时进行恢复。
-
blockcache:读缓存。它将频繁读取的数据存储在内存中,如果存储不足,它将按照
最近最少使用原则
清除多余的数据。 - memstore:写缓存。它存储尚未写入磁盘的新数据,并会在数据写入磁盘之前对其进行排序。每个 region 上的每个列族都有一个 memstore。
- hfile :将行数据按照 key\values 的形式存储在文件系统上。
region server 存取一个子表时,会创建一个 region 对象,然后对表的每个列族创建一个 store
实例,每个 store
会有 0 个或多个 storefile
与之对应,每个 storefile
则对应一个 hfile
,hfile 就是实际存储在 hdfs 上的文件。
三、hbase系统架构
3.1 系统架构
hbase 系统遵循 master/salve 架构,由三种不同类型的组件组成:
zookeeper
保证任何时候,集群中只有一个 master;
存贮所有 region 的寻址入口;
实时监控 region server 的状态,将 region server 的上线和下线信息实时通知给 master;
存储 hbase 的 schema,包括有哪些 table,每个 table 有哪些 column family 等信息。
master
为 region server 分配 region ;
负责 region server 的负载均衡 ;
发现失效的 region server 并重新分配其上的 region;
gfs 上的垃圾文件回收;
处理 schema 的更新请求。
region server
region server 负责维护 master 分配给它的 region ,并处理发送到 region 上的 io 请求;
region server 负责切分在运行过程中变得过大的 region。
3.2 组件间的协作
hbase 使用 zookeeper 作为分布式协调服务来维护集群中的服务器状态。 zookeeper 负责维护可用服务列表,并提供服务故障通知等服务:
每个 region server 都会在 zookeeper 上创建一个临时节点,master 通过 zookeeper 的 watcher 机制对节点进行监控,从而可以发现新加入的 region server 或故障退出的 region server;
所有 masters 会竞争性地在 zookeeper 上创建同一个临时节点,由于 zookeeper 只能有一个同名节点,所以必然只有一个 master 能够创建成功,此时该 master 就是主 master,主 master 会定期向 zookeeper 发送心跳。备用 masters 则通过 watcher 机制对主 hmaster 所在节点进行监听;
如果主 master 未能定时发送心跳,则其持有的 zookeeper 会话会过期,相应的临时节点也会被删除,这会触发定义在该节点上的 watcher 事件,使得备用的 master servers 得到通知。所有备用的 master servers 在接到通知后,会再次去竞争性地创建临时节点,完成主 master 的选举。
四、数据的读写流程简述
4.1 写入数据的流程
client 向 region server 提交写请求;
region server 找到目标 region;
region 检查数据是否与 schema 一致;
如果客户端没有指定版本,则获取当前系统时间作为数据版本;
将更新写入 wal log;
将更新写入 memstore;
判断 memstore 存储是否已满,如果存储已满则需要 flush 为 store hfile 文件。
更为详细写入流程可以参考:hbase - 数据写入流程解析
4.2 读取数据的流程
以下是客户端首次读写 hbase 上数据的流程:
客户端从 zookeeper 获取
meta
表所在的 region server;客户端访问
meta
表所在的 region server,从meta
表中查询到访问行键所在的 region server,之后客户端将缓存这些信息以及meta
表的位置;客户端从行键所在的 region server 上获取数据。
如果再次读取,客户端将从缓存中获取行键所在的 region server。这样客户端就不需要再次查询 meta
表,除非 region 移动导致缓存失效,这样的话,则将会重新查询并更新缓存。
注:meta
表是 hbase 中一张特殊的表,它保存了所有 region 的位置信息,meta 表自己的位置信息则存储在 zookeeper 上。
更为详细读取数据流程参考:
参考资料
本篇文章内容主要参考自官方文档和以下两篇博客,图片也主要引用自以下两篇博客:
官方文档:
更多大数据系列文章可以参见 github 开源项目: 大数据入门指南