如下代碼都是基於HBase-0.98版本。 java
compaction是將多個HFile合併爲一個HFile操做, 性能
進行compaction有以下幾個做用: this
減小HFile文件的個數, spa
HFile減小可能提升讀取性能, 線程
清除過時和刪除數據。 debug
compaction有二種類型:minor 和 major code
1)Minor操做只用來作部分文件的合併操做以及包括minVersion=0而且設置ttl的過時版本清理,不作任何刪除數據、多版本數據的清理工做。 ip
2)Major操做是對Region下的HStore下的全部StoreFile執行合併操做,會作刪除數據,多版本數據清理工做,最終的結果是整理合並出一個文件。
get
HRegionServer在啓動的時候,會啓動compactionChecker線程,compactionChecker會檢測region是否須要compaction。 requests
主要執行的邏輯以下:
protected void chore() { for (HRegion r : this.instance.onlineRegions.values()) { if (r == null) continue; for (Store s : r.getStores().values()) { try { long multiplier = s.getCompactionCheckMultiplier(); assert multiplier > 0; if (iteration % multiplier != 0) continue; if (s.needsCompaction()) { // Queue a compaction. Will recognize if major is needed. this.instance.compactSplitThread.requestSystemCompaction(r, s, getName() + " requests compaction"); } else if (s.isMajorCompaction()) { if (majorCompactPriority == DEFAULT_PRIORITY || majorCompactPriority > r.getCompactPriority()) { this.instance.compactSplitThread.requestCompaction(r, s, getName() + " requests major compaction; use default priority", null); } else { this.instance.compactSplitThread.requestCompaction(r, s, getName() + " requests major compaction; use configured priority", this.majorCompactPriority, null); } } } catch (IOException e) { LOG.warn("Failed major compaction check on " + r, e); } } } iteration = (iteration == Long.MAX_VALUE) ? 0 : (iteration + 1); } }
如代碼,遍歷onlineRegions,獲取每一個region的Store進行判斷,其中needsCompaction邏輯以下:
public boolean needsCompaction(final Collection<StoreFile> storeFiles, final List<StoreFile> filesCompacting) { int numCandidates = storeFiles.size() - filesCompacting.size(); return numCandidates >= comConf.getMinFilesToCompact(); }
minFilesToCompact由hbase.hstore.compaction.min(老版本是:hbase.hstore.compactionThreshold)控制,默認值爲3,即store下面的storeFiles數量 減去 正在compaction的數量 >=3是,須要作compaction。
needsCompaction爲true後,會調用compactSplitThread.requestSystemCompaction方法,發送compaction請求,具體內容會在compactSplitThread線程裏分析。
needsCompaction爲false後,會判斷是否爲isMajorCompaction,具體邏輯以下:
/* * @param filesToCompact Files to compact. Can be null. * @return True if we should run a major compaction. */ public boolean isMajorCompaction(final Collection<StoreFile> filesToCompact) throws IOException { boolean result = false; long mcTime = getNextMajorCompactTime(filesToCompact); if (filesToCompact == null || filesToCompact.isEmpty() || mcTime == 0) { return result; } // TODO: Use better method for determining stamp of last major (HBASE-2990) long lowTimestamp = StoreUtils.getLowestTimestamp(filesToCompact); long now = System.currentTimeMillis(); if (lowTimestamp > 0l && lowTimestamp < (now - mcTime)) { // Major compaction time has elapsed. long cfTtl = this.storeConfigInfo.getStoreFileTtl(); if (filesToCompact.size() == 1) { // Single file StoreFile sf = filesToCompact.iterator().next(); Long minTimestamp = sf.getMinimumTimestamp(); long oldest = (minTimestamp == null) ? Long.MIN_VALUE : now - minTimestamp.longValue(); if (sf.isMajorCompaction() && (cfTtl == HConstants.FOREVER || oldest < cfTtl)) { if (LOG.isDebugEnabled()) { LOG.debug("Skipping major compaction of " + this + " because one (major) compacted file only and oldestTime " + oldest + "ms is < ttl=" + cfTtl); } } else if (cfTtl != HConstants.FOREVER && oldest > cfTtl) { LOG.debug("Major compaction triggered on store " + this + ", because keyvalues outdated; time since last major compaction " + (now - lowTimestamp) + "ms"); result = true; } } else { if (LOG.isDebugEnabled()) { LOG.debug("Major compaction triggered on store " + this + "; time since last major compaction " + (now - lowTimestamp) + "ms"); } result = true; } } return result; }
未完待續。。。