一 HRegionServer启动的时候,会调用startServiceThreads,启动一些后台线程,比如compact checker,启动flushCache等线程
二HRegionServer启动后台线程的时候,会通过MemStoreFlusher
#start方法,开启FlushHandler线程.
三 只要RegionServer一直运行,FlushHandler就一直运行,然后不断从flushQueue当中poll出队首的FlushRegionEntry元素,这个FlushRegionEntry其实就是持有HRegion和重试次数的一个对象
四 然后调用flushRegion(FlushQueueEntry)方法
首先会判断Region是否是Meta Region,并且判断这Region是否有太多的StoreFiles,如果StoreFiles 数量太多:
# 如果不要split,则就进行compact操作
# FlushRegionEntry需要重新放入flushQueue,后面再执行,然后返回
其次:如果Region没有很多的StoreFiles,或者还没有达到阀值
那么这时候才开始flush region,调用HRegion#flushCache方法
然后:如果该Region已经下线,则直接返回
接着:会调用到internalFlushCache方法,这才是真正的开始flush
Cache。
流程如下:
# 如果没有可以刷新的缓存,返回,但是需要更新Region的sequence id。
# 获取该Region的更新锁的写锁,阻塞所有对该Region的更新操作
# 如果WAL不能进行flush cache,则返回
# 开始刷新前准备工作:从MemStore获取快照;从快照获取单元格数量;获取MemStore的大小
# 将数据写入文件
# 进行提交操作,主要是更新StoreFile信息,以判断是否需要compaction
# 重新设置flush之后,MemStore的大小
# 无论如何,始终都会返回一个FlushResult对象:封装的是flush有没有成功,成功之后,是否需要触发compact和split操作之类的
紧接着:根据FlushResult判断是否应该compact,是否需要split?
如果需要split,则触发split操作;否则如果需要触发compact操作则进行compact操作
prepare阶段:遍历当前Region中的所有Memstore,将Memstore中当前数据集kvset做一个快照snapshot,然后再新建一个新的kvset。后期的所有写入操作都会写入新的kvset中,而整个flush阶段读操作会首先分别遍历kvset和snapshot,如果查找不到再会到HFile中查找。prepare阶段需要加一把updateLock对写请求阻塞,结束之后会释放该锁。因为此阶段没有任何费时操作,因此持锁时间很短。
flush阶段:遍历所有Memstore,将prepare阶段生成的snapshot持久化为临时文件,临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘IO操作,因此相对比较耗时。
commit阶段:遍历所有的Memstore,将flush阶段生成的临时文件移到指定的ColumnFamily目录下,针对HFile生成对应的storefile和Reader,把storefile添加到HStore的storefiles列表中,最后再清空prepare阶段生成的snapshot。