共计 2902 个字符,预计需要花费 8 分钟才能阅读完成。
HBase 的读写流程设计
- 写数据:先预写日式 WAL,和写入内容 MemStore。WAL 用来在节点宕机后恢复写入的数据。在 MemStore 写满后会写入磁盘,生成一个新的 HFile,一旦写入不会再修改。一个列族有一个 MemStore,一个列族有多个 HFile。
- 读数据:每个列族有自己的 BlockCache,用来在内存中缓存从 HFile 读入的数据,采用 LRU 算法淘汰数据。读数据时,先从 MemStore 中尝试读取修改的数据,然后检查 BlockCache 缓存,最后才访问 HFile。
- 删除数据:先给数据打上删除标记,HFile 在大合并中才真正删除掉这些数据。
数据坐标
如何准确的定位一个数据:
rowKey -> column family -> column qualifier -> versin -> value
HBase 和关系数据库的设计思想的区别
HBase 是一种键 - 值型数据库,key 由 rowKey -> column family -> column qualifier -> versin
这些元素共同组成。
关系型数据库每个表只有两个维度,通过 id 和属性名可以得到相应的值。
数据库是用来存储事物的载体,关系数据库的局限在于从两个维度描述事物的属性,它可以方便的展现事物的一级属性,但是想要表现事物的多层级属性却不容易。如一个对象:
{
"name":{
"firstName":"Si",
"lastName":"Li"
},
"age":10
}
在关系数据库中存储这样一个对象,要么将属性都提升为一级属性,要么在 name 属性中存储一个 json 数据,要么另起一个表,专门存储 name 的数据,并且通过 name 的 id 来关联数据间的关系。
而 HBase 则是一个四维的表,描述事物的能力更强,上述问题只要建立一个 name 的列族就可以解决。
像这种 key-value 型数据库,key 可以描述无限维度的属性层级,可以更方便的描述事物,似乎是将来数据存储发展的趋势。
回过头来看关系数据库,虽然每个表只有两个维度,但可以通过表之间的关系来建立高维度属性来描述事物。从这个角度来看,关系型数据库反而道出了事物的本质。
面型列编程
一般情况下,现有数据的逻辑模型,然后物理模型根据逻辑模型进行设计和优化。而在 HBase 中,需要逆向思考,由于 HBase 中数据的物理存储遵循一定的规则,利用好这些规则来设计逻辑模型,可以大大的提高使用数据的效率。
HBase 的各层级的 key 都是有序排列的,从 row key 到 qualifier 按照字节递增排列,而 version 则按照递减顺序排列。
HBase 在一行记录里,如果某列没数据,则不会进行存储,不会占用存储空间,所以说是面向列编程。每行数据的每个列族可能会有多个 HFile,但是一个列族的数据一定要在同一个物理存储中。
HBase 不满足 ACID
- 对于每行的操作,是原子的。
- 对于多行的操作,不是原子的。
- 扫描并不是对某一时刻的数据快照的读取,如果某行数据被扫描到前有变更,则读取的数据是变更后的数据。
Hadoop Mapreduce 运行原理
工作过程:
map: 负责转化数据,将 key1、value1 输入转化 key2、value2 输出。
shuffle: 数据按照 key 分组、排序等。
reduce: 对一个 key 下的所有值进行处理,产生最后结果。
JobTracker: 负责调度、监控 mapreduce 任务。
TaskTracker: 负责实际的运行 map 或 reduce 任务。
HBase 的分布式结构
一个表被分为多个 region。RegionServer 运行在 HDFS 系统之上,是 HDFS 的客户端,负责管理多个 region。
如何定位 region?-ROOT-
、.META.
是两个特殊的表,它们也放在 region 中。-ROOT-
表只在一个 region 中,.META.
表则可能被分到多个 region 中。整个定位的过程如一个 3 层分布式 B + 树:
- ZooKeeper 管理了表的 -ROOT- 的信息。
- 先在
-ROOT-
中查找,定位拥有该数据信息的.META.
的 region。 - 从.META. 的 region 中的信息可以定位到数据在哪一个 RegionServer 里。
Mapreduce 与 HBase
HBase 既可以做 Mapreduce 的数据源,也可以作为数据目的地。
如何在 Mapreduce 中做联结操作
对于不同表中的数据,通过 rowKey 将相关数据联结起来的操作对于非关系型数据库 HBase 来说并非易事。
在 Mapreduce 中可以有以下 3 种联结的实现方式:
- 在 reduce 侧做联结。将相同 rowKey 的数据在 reduce 任务上进行联结,需要在 map 和 reduce 之间做数据洗牌和排序,有很大的 IO 开销。
- 在 map 侧联结。将两个表中,数量小的表缓存在 map 节点中,map 任务在拿到关联键后从缓存中读取相应的值,结合后进行发射。
- 在 map 中读取 HBase。一个表作为 mapreduce 的数据源,在 map 任务中从 HBase 读取另一个表中相关联的数据。
HBase 的可用性
可用性不是一个二元特性,即不是非此即彼的,而是一种程度上的模糊属性。HBase 是高可用的,在 RegionServer 发生故障时,它管理的数据会切换到其它的 RegionServer 节点上。
单一命名空间。HBase 把数据存储在一个文件系统上,一个 RegionServer 的读写数据可以为其它所有 RegionServer 读写。所以当一个 RegionServer 宕机时,其它 RegionServer 可以及时的接替它的任务。
HBase 进阶
如何建模来充分发挥 HBase 的能力
- HBase 虽然号称是无模式的数据库,但是提前设计好数据的存储 schema 可以更好的发挥 HBase 的性能。
- 列族一般要提前定义好,尽量少的改动。而列可以动态的增减,列即数据。
- HBase 没有跨行实务的概念。
- 同一列族的数据在物理上是放在一起的,在列族中找到某一个列的大体过程是一个二分查找。所以,访问宽行要比窄行开销大。
精细的描述所需数据带来的收益
- 行键:获取指定行的数据,该行下的所有相关 HFile 都会被读取。
- 列族:进一步缩小读取 HFile 范围,只读相关的 HFile。
- 列限定符:不会进一步限定列族的范围,但会减少返回数据的网络占用。
- 时间戳:进一步减少返回数据量。
反规范化
规范化是关系型数据库中的概念,指将每个表指保存自己关心的核心数据,其它的数据通过键来关联,通过 join 来查询多个表中的数据,尽量的避免同一份数据出现在两个地方,避免数据的不一致性。
反规范化是 HBase 中的概念,指行中可以冗余部分其它表的数据,以方便读取。
规范化是写优化,反规范化是读优化。
从关系型数据库到非关系型数据库
谨慎的将现有的系统从关系型数据库迁移到非关系型数据库,有时候付出的代价远比你得到的收益要高。
-
实体
- 关系型、非关系型数据库都通过表存储实体。
-
属性
- 识别属性(可以唯一的确定一条数据)在关系数据库中作为主键,在 HBase 中作为 rowKey。非识别属性在 HBase 中对应列限定符。
-
联系
- 关系型数据库通过外键,或者关系表来刻画数据之间的关系。而 HBase 中没有这种限制,只能在应用中实现数据关系的代码。
参考《HBase 实战》