HBase是什么:
- HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,它是Google Bigtable的开源实现,运行于HDFS文件系统之上,利用MapReduce处理数据,使用Zookeeper作为协同服务,因此可以容错地存储海量稀疏的数据。
特点:
- 海量数据存储,方便扩展
- 快速的随机访问,独特的设计使得写操作比读操作有时更快
- 数据存储在hdfs上,备份不用担心
- 不适合做关联查询(JOIN等)
架构图
主要组件介绍:
1. client
Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加速Hbase的访问,比如cache的.META.元数据的信息。
2. Zookeeper
HBase通过Zookeeper来做master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务。
3. HMaster
- 为RegionServer分配Region
- 维护整个集群的元数据和负载均衡
- 发现失效的Region,并分配到正常的RegionServer上
- 当RegionSever失效的时候,协调对应Hlog的拆分
4. RegionServer
- 处理来自客户端的读写请求
- 与HDFS交互
- 负责Region变大后的拆分
- 负责StoreFile的合并
5. Region
HBase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。
6. Store
HFile存储在Store中,一个Store对应HBase表中的一个列族(列簇, Column Family)。
7. MemStore
内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。
8. HFile
这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。
组件之间的关系
在Hbase中,一张表由多个的HRegion组成,一个HRegionServer中管理着多个HRegion对象。而一个HRegion由多个HStore组成,每个HStore对象都对应着表的一个列族(Column Family)。之后,一个HStore又由一个MemStore和多个StoreFile组成。这些StoreFile就是hbase存储在hdfs上的数据文件,MemStore表示还在内存中未刷新到文件上的那些数据。
合并与拆分:
MemStore中的大小达到一定的量后,会将内存中的数据刷新到磁盘,形成一个新的StoreFile。随着程序的不断运行,StoreFile的数量会越来越多,所以HRegionServer还需要定期的去合并这些StoreFile。
另外,当数据越来越多,一个Region下的StoreFile的总大小会越来越大,为了更好的查询性能,HRegionServer会负责将达到一定大小的Region分裂成两个Region。
Region的拆分明细
拆分公式:Math.min(tableRegionsCount^3 * initialSize, defaultRegionMaxFileSize)
- tableRegionCount:当前表在所有RegionServer上拥有的所有的Region数量的总和
- initialSize:如果定义了hbase.increasing.policy.initial.size,则使用该值,否则用memstore刷写值得2倍,即hbase.hregion.memstore.flush.size*2
- deffaultRegionmaxFileSize:ConstantSizeRegionSplitPolicy所用到的配置项,也就是Region的最大大小,默认是10G
刚开始只有一个Region,上限为1^3 * 128 * 2=256M
当有2个Region,上限为2^3 * 128 * 2=2048M
当有3个Region,上限为3^3 * 128 * 2=6912M
以此类推当有4个Region时候,为16G,上限达到了10GB,最大值就保持在了10G,Region数量再增加也不会增加上限
面试题
1. HBase 读流程
- client先访问zookeeper,获取meta表的(RegionServer)地址,meta表中存储了用户表的信息
- 根据namespace、表名和rowkey在meta表中找到对应的Region信息和对应RegionServer的地址
- 查找Region,先从MEMStore找数据,若没有,再到BlockCache里面读
- BlockCache也没有,则到StoreFile里面读
- 若是从StoreFile里读的数据,则先写入BlockCache再返回给客户端
2. HBase 写流程
- client想RegionServer发送写请求
- RegionServer先将数据写到HLog(Write Ahead Log),为了数据的持久化和恢复
- RegionServer将数据写到内存MemStore
- 通知client写成功
3. 数据flush过程
- 当MemStore数据达到阈值(默认是128M,老版本是64M),将内存中的数据刷写到硬盘,然后删除内存中的数和HLog中的历史数据
- 将数据存储到HDFS中
- 在HLog中做标记点
flush触发条件:
- Region中所有MemStore占用内存超过相关阈值(hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier,128 * 4 = 512M)
- 整个RegionServer的MemStore占用内存总和大于相关阈值(整个 RegionServer 的 MemStore 占用内存总和大于堆内存的0.4*0.95 则开始刷写,如果达到堆内存的0.4则阻塞客户端对RegionServer的写入
)- WAL数量(HLog)大于相关阈值
- 定期自动刷写,默认是1小时
- 手动刷写(API接口或者在shell中执行刷写命令)
4. 数据的合并过程
- 当数据块(HFile)达到3块时,HMaster触发合并操作,Region将数据块加载到本地,进行合并
- 当第一次合并的数据超过256M(此值是根据配置算出的),进行拆分,将拆分后的Region分配给不同的RegionServer管理
- 当RegionServer宕机后,将RegionServer上的HLog拆分,(HLog是之前同步到HDFS的),然后分配给不同的RegionServer处理,修改meta元数据表
5. 分裂成的两个Region大小一定一样吗?
不一定,因为切分Region时,是根据Rowkey来的,刚好中间的middleRowkey比较大的话,则包含middleRowkey的部分更大。
6. rowkey的设计原则:
- 长度原则:一般设计成定长,10-100byte,合理利用
时间戳
,_
、|
等字符 - 散列原则:尽量使rowkey均匀分布在各个HBASE节点上
- 唯一原则:设计上必须保证rowkey的唯一性
- 排序原则:这个看情况使用,rowkey是按照ASCII有序的,有时时间戳反转也很有帮助