1.4 HBase结构
1.4.2 HBase 的表、列和单元格
- 基本单位是column
- 多column组成row
- 一个row有唯一rowkey
- 每个column有多个版本,多个版本存储在单元格(cell)中
- 行序是按照字典顺序进行排序的,意思是从左到右一次对比每一个键
关于排序:
排列顺序如果跟预期的不一样,需要补键,比如 row-1 永远小于 row-2,无论后面是什么,将始终按照这个顺序排列
思考
这有可能影响到balance策略,假设你根据时间戳来做rowkey,那么会出现最后一个节点,数据不断增加而前面的节点数据不变,这个过程会持续到达到rebalance的阀值,然后触发rebalance过程,在rebalance 的时候系统性能急剧下降。当此次rebalance 完成后,只是保证了暂时的数据平衡,很快最后一个节点又会出现达到rebalance阀值的情况,就会带来一个有规律的间歇性的系统性能下降,十分危险。
列族的作用
若干列组成列族(column family),作用是:
- 构建数据的语义边界或者局部边界
- 有助于设置压缩或者指示他们存储在内存中
- 一个列族的所有列存储在同一个底层存储文件里面,这个文件叫做HFile
列族使用注意点
- 列族不能修改的太频繁,数量也不能太多,在当前的实现中如果列族大于几十个会出现bug,实际情况可能还小的多
- 引用列的格式为 family:qualifier , family 就是列族名, qualifier就是列名,比如 log:time 是获取 log这个列族中的time列,列是无限的可以达到几百万
列的时间戳
每个列的时间戳有以下特性
- 默认由系统指定,也可以手动指定
- 可以通过不同的时间戳区分版本
单元格的版本
- 用户可以i指定每个值所能存储的最大版本数
- 支持谓词删除(predicate deletion)(暂时不知道什么意思):比如只允许用户存储过去一周的值,不过这些值是未解释的字节数组
Hbase的一种应用场景
webtable: 存储从互联网上抓取的网页。行键是反转的url比如org.hbase.www ,有一个用于存储HTML的列叫 contents,还有其他列族,比如 anchor用户存储外向链接和入站链接,还有用于存储元数据的列列族language。 content列族用多版本来存储html,可以查询到旧的html。例如帮助分析页面变化频率就可以把时间戳设置成抓取页面的次数
原子性
行数据的存取是原子性的,目前不支持跨行事务和跨表事务。由于行数据是原子性的,所以可以达到强一致性(表示怀疑)
1.4.3 自动分区
Hbase中扩展和负载均衡的基本单元成为region
- region是行键连续排列的存储区间
- 如果region太大就会动态拆分
- 如果region太小就会合并以节省空间
- region相当于传统数据库的分区表
region是怎么分区的
- 一开始是有一个region,当这个region大到一定的值的时候就会从中间键(middle key,region中间的那个行键)处将这个region拆分为大致相等的两个子region。
- 一个region服务器可以有多个region。
- Hbase不支持在线的region合并,但是可以离线合并
- region的拆分非常快,接近于瞬间,因为并没有改变存储的位置
- 如果一个region server的负载过大会触发region迁移,它会将region迁移到别的region server上
思考
- 如果是这样来推导那么系统中的region大小会平均分布为大概是 阀值/2 那么大。
- 高负载情况下是否会出现触发region迁移,但是region迁移又增加负载的恶性循环?
建议
- 每台服务器的最佳加载数量是 10~1000
- 每个region最佳大小是 1G~2G (基于现有硬件推算)
1.4.4 存储API
API提供了
- 建表
- 删表
- 增加列族
- 删除列族
- 修改表
- 修改列族元数据(压缩,设置块大小)
- 行键值的增加,删除,查找
scan API
scan可以
- 限定返回的列或者返回的版本数
- 可以设置过滤器
系统支持单行事务,进一步实现单行键下存储的数据的 读-修改-写(read-modify-write)序列
单元格的值可以当计数器用,并且支持原子更新,意味着这个计数器可以在一个操作中实现读写,客户端可以基于此实现一个全局强一致的计数器
协处理器(coprocessor): 可以在服务器的地址空间执行来自客户端的代码。用于实现轻量级的批处理作业,或者使用表达式分析或者汇总数据
通过包装器可以将表转换成MapReduce的输入输出目标
1.4.5 实现
数据存储在 存储文件(store file)中,称为HFile
- HFile中的键值是经过排序的
- 文件内部是连续的块,块的索引信息存储在尾部
- HFile被加载到内存中时,索引会优先加载到内存中
- 每个块默认是64KB
每次更新数据的时候发生了什么
- 数据记录到提交日志(commit log),在HBase中称之为 预写日志(write-ahead log, WAL)(存储在HDFS系统上)
- 数据写入内存中的 memstore
- 写入的数据超过阀值,数据被写入HFile
- 数据移出memstore,丢弃提交日志。采用滚动memstore可以实现不阻塞系统读写,即用空的新memstore获取更新数据,将旧的满的memstore转换成一个文件,由于memstore中的数据本来就排序好了,所以存储的时候不用再次排序
当记录被固化到HFile上之后,删除键值对并不是直接删除,而是做个删除标记delete marker。
查询结果是memstore+HFile的数据。
查询的时候用不到WAL,只有服务器内存中的数据在服务器崩溃前没有写入磁盘,而后进行恢复数据时才会用到WAL。
管家机制
HFile过多的时候有管家机制来处理,合并有两种类型:
minor合并:多个小文件合并成一个大文件,由于是多路归并所以速度快
major压缩合并:将region中一个列族的若干个HFile重写为一个新HFile。合并扫描所有键值对,顺序重写所有数据,重写数据的过程中会略过做了删除标记的数据。断言删除此时生效。
master 负责负载均衡,将繁忙服务器中的region移到负载轻的服务器中
版权声明:本文为博主原创文章,未经博主允许不得转载。