0.94- 版本 Client访问用户数据之前需要首先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,如下图:
0.96+ 删除了root 表,改为zookeeper里面的文件,如下图 A, 以读为例,寻址示意图如B
图A
图B
Write:
当客户端发起一个Put请求时,首先根据RowKey寻址,从hbase:meta表中查出该Put数据最终需要去的HRegionServer
客户端将Put请求发送给相应的HRegionServer,在HRegionServer中它首先会将该Put操作写入WAL日志文件中(Flush到磁盘中),如下图:
完WAL日志文件后,HRegionServer根据Put中的TableName和RowKey找到对应的HRegion,并根据Column Family找到对应的HStore
将Put数据写入到该HStore的MemStore中。此时写成功,并返回通知客户端
上一节介绍过,MemStore是一个In Memory Sorted Buffer,在每个HStore中都有一个MemStore,即它是一个HRegion的一个Column Family对应一个实例。
它的排列顺序以RowKey、Column Family、Column的顺序以及Timestamp的倒序,如下示意图:
每一次Put请求都是先写入到MemStore中,当MemStore满后会Flush成一个新的StoreFile(底层实现是HFile),即一个HStore(Column Family)可以有0个或多个StoreFile(HFile)
注意:MemStore的最小Flush单元是HRegion而不是单个MemStore, 这就是建议使用单列族的原因,太多的Column Family一起Flush会引起性能问题
MemStore触发Flush动作的时机:
当一个MemStore的大小超过了hbase.hregion.memstore.flush.size的大小,此时当前的HRegion中所有的MemStore会Flush到HDFS中
当全局MemStore的大小超过了hbase.regionserver.global.memstore.upperLimit的大小,默认40%的内存使用量。此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush顺序是MemStore大小的倒序,直到总体的MemStore使用量低于hbase.regionserver.global.memstore.lowerLimit,默认38%的内存使用量
待确认:一个HRegion中所有MemStore总和作为该HRegion的MemStore的大小还是选取最大的MemStore作为参考?
当前HRegionServer中WAL的大小超过了hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs的数量,当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush使用时间顺序,最早的MemStore先Flush直到WAL的数量少于hbase.regionserver.hlog.blocksize * hbase.regionserver.max.logs
注意:因为这个大小超过限制引起的Flush不是一件好事,可能引起长时间的延迟
在MemStore Flush过程中,还会在尾部追加一些meta数据,其中就包括Flush时最大的WAL sequence值,以告诉HBase这个StoreFile写入的最新数据的序列,那么在Recover时就直到从哪里开始。在HRegion启动时,这个sequence会被读取,并取最大的作为下一次更新时的起始sequence,如下图:
Compaction:
MemStore每次Flush会创建新的HFile,而过多的HFile会引起读的性能问题,HBase采用Compaction机制来解决这个问题
HBase中Compaction分为两种:Minor Compaction和Major Compaction