基础结构¶
B+树¶

几个特征¶
- 有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
- 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针(卫星数据),且叶子结点本身依关键字的大小自小而大顺序链接。
- 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
优势¶
- 单一节点存储更多的元素,使得查询的IO次数更少;
- 所有查询都要查找到叶子节点,查询性能稳定;
- 所有叶子节点形成有序链表,便于范围查询;
LSM 树¶
LSM树,即日志结构合并树(Log-Structured Merge-Tree)。其实它并不属于一个具体的数据结构,它更多是一种数据结构的设计思想。
大多NoSQL数据库核心思想都是基于LSM来做的,只是具体的实现不同。
LSM树原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。
LSM树能让我们进行顺序写磁盘,从而大幅提升写操作,作为代价的是牺牲了一些读性能。
LSM 结构和B-Tree结构的比较¶
传统关系型数据库使用btree或一些变体作为存储结构,能高效进行查找。但保存在磁盘中时它也有一个明显的缺陷,那就是逻辑上相离很近但物理却可能相隔很远,这就可能造成大量的磁盘随机读写。因此,BTree引擎的数据库,磁盘随机查找能力是其性能的瓶颈。
大部分NoSQL数据库,以LSM为存储引擎。通过内存+顺序读写的方式,将DB的瓶颈转换为磁盘顺序写。
选择时可以考虑以下:
- 在SSD的支撑下BTree能够发挥相当优秀的性能,而对于廉价机械硬盘,LSM可能有更好表现。
- 考虑磁盘限制,LSM写性能较好,BTree查询性能较好。
- 如果有频繁的修改,LSM的性能更好;
HBASE 架构分析¶
Features¶
- 强一致性读写,尤其适合高速计数器应用。
- 通过regions机制自动分片。
- 自动Failover
- HBase支持HDFS作为其分布式文件系统。
- HBase支持块缓存和布隆过滤器,以实现高容量查询优化。
使用场景¶
- 亿级别的数据
- 无需使用typed columns,secondary indexes,事务,高级查询语句
Catalog Table¶
hbase:meta¶
hbase:meta 保存了所有regions的位置信息,而hbase:meta的位置保存在Zookeeper中。
hbase:meta 的架构:
key: [table],[region start key],[region id]
values:
- info: regioninfo 序列化的HRegionInfo实例
- info: server 保存该RegionServer的server:port信息
- info: serverstartcode 该RegionServer保存该region的开始时间
- info: splitA/B 当table发生splitting时,会创建这两张,表示该regions的子regionx信息(同regioninfo),单分裂完成后,这两个columns会被删除
RegionServer¶
当HBase启动时,regions按照以下步骤进行分配:
- Master创建AssignmentManager实例
- AssignmentManager通过hbase:meta的判断当前存在的region
- 如果region 配置合法,那么配置被保留
- 如果配置不合法,Master启动LoadBalancerFactory实例,重新分配region
- 更新hbase:meta表,启动RegionServer进程
RegionServer 的 Failover 进程:
- 当RegionServer关闭时,对应的regions立刻变成不可用
- Master 发现 RegionServer 故障
- Master 触发Region 重新分配
- 正在进行的查询开始重试,并切换到另一个RegionServer运行
Region¶
hbase:meta的状态保存在ZooKeeper中,而其他Region的状态保存在hbase:meta表中。
Splits¶
Region的Splits线程在RegionServer中独立运行,Master不参加Splits操作。RegionsServer将父region下线,然后拆分,在hbase:meta中添加子region的信息,并将相关信息汇报给Master。
用户可以定制表的Splits策略:
- 全局策略:hbase.regionserver.region.split.policy
- 通过JAVA API 可以表结构中为单个表定制策略
已知拆分策略:
| 策略 | 说明 |
|---|---|
| ConstantSizeRegionSplitPolicy | 根据公式min(r^2*flushSize,maxFileSize)确定split的maxFileSize,其中r为在线region个数,maxFileSize由hbase.hregion.max.filesize指定。 |
| IncreasingToUpperBoundRegionSplitPolicy | ConstantSizeRegionSplitPolicy,仅仅当region大小超过常量值(hbase.hregion.max.filesize大小)时,才进行拆分。 |
| DelimitedKeyPrefixRegionSplitPolicy | 保证以分隔符前面的前缀为splitPoint,保证相同RowKey前缀的数据在一个Region中 |
| KeyPrefixRegionSplitPolicy | 保证具有相同前缀的row在一个region中(要求设计中前缀具有同样长度)。指定rowkey前缀位数划分region,通过读取table的prefix_split_key_policy.prefix_length属性,该属性为数字类型,表示前缀长度,在进行split时,按此长度对splitPoint进行截取。此种策略比较适合固定前缀的rowkey。当table中没有设置该属性,或其属性不为Integer类型时,指定此策略效果等同与使用IncreasingToUpperBoundRegionSplitPolicy。 |
手动 Splits¶
可以在创建Table时进行预拆分,或者使用一段时间后对Table手工拆分。
下面几种情况,出现时用户可以手工进行splits:
- 存在某个“热点Region”
- 在群集中RegionServers数量大幅增加之后,快速分散负载。
- 进行bulk-load之后,region之间可能分区不均衡。
PS: 使用时间作为row key,导致最后一个region过热,其余region全部空闲。因此,HBase中的row key不能设计为时间戳,或者任何递增的字符