都知道memstore大小到一定程度后会flush到disk上去,这个大小是由hbase.hregion.memstore.flush.size定义的。flush的时候也不是说马上就flush出去,会有个检查,就是下面这个方法了:
code:hbase 0.20.6, MemStoreFlusher.java
/* * A flushRegion that checks store file count. If too many, puts the flush * on delay queue to retry later. * @param fqe * @return true if the region was successfully flushed, false otherwise. If * false, there will be accompanying log messages explaining why the log was * not flushed. */ private boolean flushRegion(final FlushQueueEntry fqe) { HRegion region = fqe.region; if (!fqe.region.getRegionInfo().isMetaRegion() && isTooManyStoreFiles(region)) { if (fqe.isMaximumWait(this.blockingWaitTime)) { LOG.info("Waited " + (System.currentTimeMillis() - fqe.createTime) + "ms on a compaction to clean up 'too many store files'; waited " + "long enough... proceeding with flush of " + region.getRegionNameAsString()); } else { // If this is first time we've been put off, then emit a log message. if (fqe.getRequeueCount() <= 0) { // Note: We don't impose blockingStoreFiles constraint on meta regions LOG.warn("Region " + region.getRegionNameAsString() + " has too many " + "store files; delaying flush up to " + this.blockingWaitTime + "ms"); } this.server.compactSplitThread.compactionRequested(region, getName()); // Put back on the queue. Have it come back out of the queue // after a delay of this.blockingWaitTime / 100 ms. this.flushQueue.add(fqe.requeue(this.blockingWaitTime / 100)); // Tell a lie, it's not flushed but it's ok return true; } } return flushRegion(region, false); }
这个code逻辑是:
1. 如果是meta region,没话说,立即flush出去吧,因为meta region优先级高啊;
2. 如果是user的region,先看看是不是有太多的StoreFile了,这个storefile就是每次memstore flush造成的,flush一次,就多一个storefile,所以一个HStore里面会有多个storefile(其实就是hfile)。判断多不多的一个阈值是由hbase.hstore.blockingStoreFiles定义的;
Note:要弄清楚的就是,Hbase将table水平划分成Region,region按column family划分成Store,每个store包括内存中的memstore和持久化到disk上的HFile。
还有一个check flush的地方,就是HRegion里面
/* * Check if resources to support an update. * * Here we synchronize on HRegion, a broad scoped lock. Its appropriate * given we're figuring in here whether this region is able to take on * writes. This is only method with a synchronize (at time of writing), * this and the synchronize on 'this' inside in internalFlushCache to send * the notify. */ private void checkResources() { // If catalog region, do not impose resource constraints or block updates. if (this.getRegionInfo().isMetaRegion()) return; boolean blocked = false; while (this.memstoreSize.get() > this.blockingMemStoreSize) { requestFlush(); if (!blocked) { LOG.info("Blocking updates for '" + Thread.currentThread().getName() + "' on region " + Bytes.toStringBinary(getRegionName()) + ": memstore size " + StringUtils.humanReadableInt(this.memstoreSize.get()) + " is >= than blocking " + StringUtils.humanReadableInt(this.blockingMemStoreSize) + " size"); } blocked = true; synchronized(this) { try { wait(threadWakeFrequency); } catch (InterruptedException e) { // continue; } } } if (blocked) { LOG.info("Unblocking updates for region " + this + " '" + Thread.currentThread().getName() + "'"); } }
这里的memstoreSize是一个region中所有memstore的总大小,blockingMemStoreSize计算的公式如下:
blockingMemStoreSize=hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block.multiplier
就是说,对整个HRegion来说,所有memstore的总大小大于multiplier个memstore阈值的时候,就开始阻止客户端的更新了,这样是为了避免内存中的数据太多吧。