本文对最近接触到Hbase相关的资料做个简单整理, 主要包含了数据模型, 底层存储结构, 以及分布式模型.Hbase是Google发表的论文Bigtable的开源实现, 文中对于BigTable和Hbase中的对应的名词在不引起歧义的情况下可能混合使用, 不做区分.
部分可能替换如下:
Hbase | BigTable |
---|---|
Region Server/Data Node | Tablet Server |
Region | Tablet |
MemStore | Memtable |
StoreFile | SStable |
数据模型
数据模型在这里是指数据库对外提供的抽象的数据操作模型, 不涉及底层的存储, 在有些资料也叫概念视图. 例如对MySQL来说, 我们可以建立一个多列的表格, 每列可以指定属性, 那么表就是MySQL的数据模型, 相应的, 对于Redis, 数据模型是KV(Key-Value), 用户可以进行简单的Key-Value的操作. Hbase的数据模型是也是表, 但是这个表和关系型数据库中的表有所不同. 它是一个稀疏表. 在这个表中, 用户可以定义一些列族(Column Family), 每个列族下面可以定义列名(Column qualifier), 然后每行的数据可以定义行键(Row Key), 通过指定唯一的行键以及相应的列族和列名, 就可以找到一个最小的存储单元, 称为Cell. 每个Cell中有保存了数据的多个版本, 每个版本有一个时间戳(timestamp). 所以, 有些资料也把Hbase的数据模型看成是一个KV结构, Key是四维的元组(Column key,Column Famliy, Row Key, timestamp), Value是一个字符串.
我们给出一张图来说明为什么是稀疏表以及KV结构.
图片取自: http://web.cs.wpi.edu/~cs525/s13-MYE/lectures/5/HBase.pptx
这是Bigtable论文中的一张图, 其解释了Hbase的数据模型. 和关系型的表中直接指定每列的属性名和属性这种方式不同, 这里我们的列首先有用户预先指定的一些Column Family, 在Column Family的基础上, 进一步指定Column Key 作为列的名字. 用户插入数据, 需要指定Row Key, Column Family, 以及Column Key, 然后就可以在一个Cell中存一个字符串型的Value. 但是, 这个插入到此为止, 这一个大表中的其他列不需要因为这条插入而增加数据, 而这关系型表结构中, 一次插入一行数据, 当前行的每列都需要有数据, 这也就是两种表结构的区别, 所以其数据模型可以看成一个稀疏表.
索引与数据放置
Hbase根据行键来建立索引, 按照列来进行数据存储, 这里首先简单说明行存储和列存储:
- 行存储: 行存储是(行 行 行)这种形式存满磁盘页, 这样如果只有部分属性是有用的, 就会造成带宽浪费, 因为读取了很多没有用的列. 传统的关系型数据库, 使用了行存储的方式.
- 列存储: 列存储适合于需要一次读取部分列数据的操作, 如常见的数据分析场景(对某列求平均等操作), 但是其Join操作要读取不同的磁盘页, 代价比较大. 本文参考的课程的一个作业就是在Hbase上实现Join操作. Hbase不是严格的列式, 因为是列族层次的列,不是每个小列.
对于Hbase的一个表来说, 其有很多的列族, 不同的列族分开在不同的文件中进行存储. 同一个列族存在一起, 列族下面的列可以动态增加. 对于时间戳,如果没有给出参数, 查询的时候返回的是最新的版本. 提供了保留历史的n个版本和保留最近n天的版本两种方案.
行键是字符串, 存成字节数组, 根据字典序排序, 提供了直接访问, 范围访问, 和全表扫描三种访问的方式. 其关注的要点如下:
列族数量不能太多, 一般就几十个. 并且要建表的时候就创建好. 列族可被