memstore的flush流程分析
memstore的flush发起主要从以下几个地方进行:
a.在HRegionServer调用multi进行更新时,检查是否超过全局的memstore配置的最大值与最小值,
如果是,发起一个WakeupFlushThread的flush请求,如果超过全局memory的最大值,需要等待flush完成。
b.在HRegionServer进行数据更新时,调用HRegion.batchMutate更新store中数据时,
如果region.memstore的大小超过配置的regionmemstore size时,发起一个FlushRegionEntry的flush请求,
c.client端显示调用HRegionServer.flushRegion请求
d.通过hbase.regionserver.optionalcacheflushinterval配置,
默认3600000ms的HRegionServer.PeriodicMemstoreFlusher定时flush线程
flush的执行过程
flush的具体执行通过MemStoreFlusher完成,当发起flushRequest时,
会把flush的request添加到flushQueue队列中,同时把request添加到regionsInQueue列表中。
MemStoreFlusher实例生成时会启动MemStoreFlusher.FlushHandler线程实例,
此线程个数通过hbase.hstore.flusher.count配置,默认为1
privateclassFlushHandler extendsHasThread{
@Override
publicvoidrun(){
while(!server.isStopped()){
FlushQueueEntryfqe = null;
try{
wakeupPending.set(false);// allow someone to wake us up again
从队列中取出一个flushrequest,此队列是一个阻塞队列,如果flushQueue队列中没有值,
等待hbase.server.thread.wakefrequency配置的ms,默认为10*1000
fqe= flushQueue.poll(threadWakeFrequency,TimeUnit.MILLISECONDS);
if(fqe ==null|| fqeinstanceofWakeupFlushThread) {
如果没有flushrequest或者flushrequest是一个全局flush的request
检查所有的memstore是否超过hbase.regionserver.global.memstore.lowerLimit配置的值,默认0.35
if(isAboveLowWaterMark()){
LOG.debug("Flushthread woke up because memory above low water="
-
-
-
-
-
-
-
StringUtils.
humanReadableInt(globalMemStoreLimitLowMark));
-
-
-
-
-
-
超过配置的最小memstore的值,flsuh掉最大的一个memstore的region
此执行方法的流程分析见MemStoreFlusher.flushOneForGlobalPressure流程分析
if(!flushOneForGlobalPressure()){
....................此处部分代码没有显示
Thread.sleep(1000);
没有需要flush的region,叫醒更新线程的等待,
HregionServer执行数据更新的相关方法如果发现memstore的总和超过配置的最大值时,会wait更新线程,等待flush
wakeUpIfBlocking();
}
//Enqueue another one of these tokens so we'll wake up again
发起另一个叫醒的全局flushrequest,生成WakeupFlushThread的request
wakeupFlushThread();
}
continue;
}
正常的flushrequest,
单个regionmemstore大小超过hbase.hregion.memstore.flush.size配置的值,默认1024*1024*128L
此执行方法的流程分析见MemStoreFlusher.flushRegion
FlushRegionEntry fre= (FlushRegionEntry) fqe;
if(!flushRegion(fre)){
break;
}
} catch(InterruptedException ex){
continue;
} catch(ConcurrentModificationException ex){
continue;
} catch(Exception ex){
LOG.error("Cacheflusher failed for entry " + fqe,ex);
if(!server.checkFileSystem()){
break;
}
}
}
结束MemStoreFlusher的线程调用,通常是regionserverstop
synchronized(regionsInQueue){
regionsInQueue.clear();
flushQueue.clear();
}
//Signal anyone waiting, so they see the close flag
wakeUpIfBlocking();
LOG.info(getName()+ " exiting");
}
}
MemStoreFlusher.flushOneForGlobalPressure流程分析
此方法主要用来取出所有region是memstore最大的一个region,并执行flush操作。
privatebooleanflushOneForGlobalPressure(){
SortedMap<Long,HRegion>regionsBySize=
server.getCopyOfOnlineRegionsSortedBySize();
Set<HRegion>excludedRegions= newHashSet<HRegion>();
booleanflushedOne= false;
while(!flushedOne){
//Find the biggest region that doesn't have too many storefiles
//(might be null!)
取出memstore占用最大的一个region,但这个region需要满足以下条件:
a.region的writestate.flushing==false,同时writestate.writesEnabled==true,非readonly
b.region中所有的store中的storefile的个数小于hbase.hstore.blockingStoreFiles配置的值,默认为7
此处去找region时,是按region的memstore的大小从大到小排序组成。取出满足以上条件的最大的memstore的region
如果都不满足,返回null
HRegion bestFlushableRegion= getBiggestMemstoreRegion(
regionsBySize,excludedRegions,true);
//Find the biggest region, total, even if it might have too manyflushes.
取出memstore占用最大的一个region,但这个region需要满足以下条件:
a.region的writestate.flushing==false,同时writestate.writesEnabled==true,非readonly
b.按region的memstore的大小从大到小排序组成。取出满足以上条件的最大的memstore的region
如果都不满足,返回null,此处不检查region中是否有store的文件个数超过指定的配置值。
HRegion bestAnyRegion= getBiggestMemstoreRegion(
regionsBySize,excludedRegions,false);
如果没有拿到上面第二处检查的region,那么表示没有需要flush的region,返回,不进行flush操作。
if(bestAnyRegion== null){
LOG.error("Abovememory mark but there are no flushable regions!");
returnfalse;
}
得到最需要进行flush的region,