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实战》