架构分析
1、HMaster
负责管理HBase元数据,即表的结构、表存储的Region等元信息。
负责表的创建,删除和修改(因为这些操作会导致HBase元数据的变动)。
负责为HRegionServer分配Region,分配好后也会将元数据写入相应位置(后面会详细讲述放在哪)。
如果对可用性要求较高,它需要做HA高可用(通过Zookeeper)。但是HMaster不会去处理Client端的数据读写请求,因为这样会加大其负载压力,具体的读写请求它会交给HRegionServer来做。
2、HRegionServer
一个RegionServer里有多个Region。
处理Client端的读写请求(根据从HMaster返回的元数据找到对应的Region来读写数据)。
管理Region的Split分裂、StoreFile的Compaction合并。
一个RegionServer管理着多个Region,在HBase运行期间,可以动态添加、删除HRegionServer。
3、HRegion
一个HRegion里可能有1个或多个Store。
HRegionServer维护一个HLog。
HRegion是分布式存储和负载的最小单元。
表通常被保存在多个HRegionServer的多个Region中。
因为HBase用于存储海量数据,故一张表中数据量非常之大,单机一般存不下这么大的数据,故HBase会将一张表按照行水平将大表划分为多个Region,每个Region保存表的一段连续数据。 初始只有1个Region,当一个Region增大到某个阈值后,便分割为两个。
4、Store
Store是存储落盘的最小单元,由内存中的MemStore和磁盘中的若干StoreFile组成。
一个Store里有1个或多个StoreFile和一个memStore。
每个Store存储一个列族。
HBase 读写过程
写数据流程
Client访问ZK,根据ROOT表获取meta表所在Region的位置信息,并将该位置信息写入Client Cache。
(注:为了加快数据访问速度,我们将元数据、Region位置等信息缓存在Client Cache中。)
Client读取meta表,再根据meta表中查询得到的Namespace、表名和RowKey等相关信息,获取将要写入Region的位置信息,最后client端会将meta表写入Client Cache。
Client向上一步HRegionServer发出写请求,HRegionServer先将操作和数据写入HLog(预写日志,Write Ahead Log,WAL),再将数据写入MemStore,并保持有序。(若MemStore中的数据有丢失,则可以总HLog上恢复)
(联想:HDFS中也是如此,EditLog写入时机也是在真实读写之前发生)
当MemStore的数据量超过阈值时,将数据溢写磁盘,生成一个StoreFile文件。
当Store中StoreFile的数量超过阈值时,将若干小StoreFile合并(Compact)为一个大StoreFile。
当Region中最大Store的大小超过阈值时,Region分裂(Split),等分成两个子Region。
Memstore Flush触发条件
1、Memstore级别限制:当Region中任意一个MemStore的大小达到了上限(hbase.hregion.memstore.flush.size,默认128MB),会触发Memstore刷新。
2、Region级别限制:当Region中所有Memstore的大小总和达到了上限(hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size,默认 2* 128M = 256M),会触发memstore刷新。
3、Region Server级别限制:当一个Region Server中所有Memstore的大小总和达到了上限(hbase.regionserver.global.memstore.upperLimit * hbase_heapsize,默认 40%的JVM内存使用量),会触发部分Memstore刷新。Flush顺序是按照Memstore由大到小执行,先Flush Memstore最大的Region,再执行次大的,直至总体Memstore内存使用量低于阈值(hbase.regionserver.global.memstore.lowerLimit * hbase_heapsize,默认 38%的JVM内存使用量)。
4、当一个Region Server中HLog数量达到上限(可通过参数hbase.regionserver.maxlogs配置)时,系统会选取最早的一个 HLog对应的一个或多个Region进行flush
5、HBase定期刷新Memstore:默认周期为1小时,确保Memstore不会长时间没有持久化。为避免所有的MemStore在同一时间都进行flush导致的问题,定期的flush操作有20000左右的随机延时。
6、手动执行flush:用户可以通过shell命令 flush ‘tablename’或者flush ‘region name’分别对一个表或者一个Region进行flush。
HBase读数据流程
1,Client先访问zookeeper,从meta表读取region的位置,然后读取meta表中的数据。meta中又存储了用户表的region信息。
2,根据namespace、表名和rowkey在meta表中找到对应的region信息
3,找到这个region对应的regionserver
4.去对应的regionserver找Block Cache 中读取数据
4,如果没有读取到查找对应的region
5,先从MemStore找数据,如果没有,再到StoreFile上读(为了读取的效率)。
6,将读取结果放入blockcache
( BlockCache主要提供给读使用。读请求先到memstore中查数据,查不到就到blockcache中查,再查不到就会到磁盘上读,并把读的结果放入blockcache。由于blockcache是一个LRU,因此blockcache达到上限(heapsize * hfile.block.cache.size)后,会启动淘汰机制,淘汰掉最老的一批数据。 )
Compaction分为两种:
major compaction
将Store下面所有StoreFile合并为一个StoreFile,此操作会删除其他版本的数据(不同时间戳的)
minor compaction
选取Store下的部分StoreFile,将它们合并为一个StoreFile,此操作不会删除其他版本数据。
Region分割(Split)
目的:实现数据访问的负载均衡。
做法:利用Middle Key将当前Region划分为两个等分的子Region。需要指出的是:Split会产生大量的I/O操作,Split开始前和Split完成后,HRegionServer都会通知HMaster。Split完成后,由于Region映射关系已变更,故HRegionServer会更新meta表。