HBASE-10501 Improve IncreasingToUpperBoundRegionSplitPolicy to avoid too many regions.

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1569507 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
larsh 2014-02-18 19:43:30 +00:00
parent 6b81ac7c93
commit 09e16b32d0
2 changed files with 24 additions and 19 deletions

View File

@ -29,30 +29,34 @@ import org.apache.hadoop.hbase.HTableDescriptor;
/** /**
* Split size is the number of regions that are on this server that all are * Split size is the number of regions that are on this server that all are
* of the same table, squared, times the region flush size OR the maximum * of the same table, cubed, times 2x the region flush size OR the maximum
* region split size, whichever is smaller. For example, if the flush size * region split size, whichever is smaller. For example, if the flush size
* is 128M, then on first flush we will split which will make two regions * is 128M, then after two flushes (256MB) we will split which will make two regions
* that will split when their size is 2 * 2 * 128M = 512M. If one of these * that will split when their size is 2^3 * 128M*2 = 2048M. If one of these
* regions splits, then there are three regions and now the split size is * regions splits, then there are three regions and now the split size is
* 3 * 3 * 128M = 1152M, and so on until we reach the configured * 3^3 * 128M*2 = 6912M, and so on until we reach the configured
* maximum filesize and then from there on out, we'll use that. * maximum filesize and then from there on out, we'll use that.
*/ */
public class IncreasingToUpperBoundRegionSplitPolicy public class IncreasingToUpperBoundRegionSplitPolicy
extends ConstantSizeRegionSplitPolicy { extends ConstantSizeRegionSplitPolicy {
static final Log LOG = static final Log LOG =
LogFactory.getLog(IncreasingToUpperBoundRegionSplitPolicy.class); LogFactory.getLog(IncreasingToUpperBoundRegionSplitPolicy.class);
private long flushSize; private long initialSize;
@Override @Override
protected void configureForRegion(HRegion region) { protected void configureForRegion(HRegion region) {
super.configureForRegion(region); super.configureForRegion(region);
Configuration conf = getConf(); Configuration conf = getConf();
this.initialSize = conf.getLong("hbase.increasing.policy.initial.size", -1);
if (this.initialSize > 0) {
return;
}
HTableDescriptor desc = region.getTableDesc(); HTableDescriptor desc = region.getTableDesc();
if (desc != null) { if (desc != null) {
this.flushSize = desc.getMemStoreFlushSize(); this.initialSize = 2*desc.getMemStoreFlushSize();
} }
if (this.flushSize <= 0) { if (this.initialSize <= 0) {
this.flushSize = conf.getLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, this.initialSize = 2*conf.getLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE,
HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE); HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE);
} }
} }
@ -90,10 +94,11 @@ extends ConstantSizeRegionSplitPolicy {
* @return Region max size or <code>count of regions squared * flushsize, which ever is * @return Region max size or <code>count of regions squared * flushsize, which ever is
* smaller; guard against there being zero regions on this server. * smaller; guard against there being zero regions on this server.
*/ */
long getSizeToCheck(final int tableRegionsCount) { protected long getSizeToCheck(final int tableRegionsCount) {
return tableRegionsCount == 0? getDesiredMaxFileSize(): // safety check for 100 to avoid numerical overflow in extreme cases
return tableRegionsCount == 0 || tableRegionsCount > 100 ? getDesiredMaxFileSize():
Math.min(getDesiredMaxFileSize(), Math.min(getDesiredMaxFileSize(),
this.flushSize * (tableRegionsCount * (long)tableRegionsCount)); this.initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount);
} }
/** /**

View File

@ -76,9 +76,9 @@ public class TestRegionSplitPolicy {
// Set max size for this 'table'. // Set max size for this 'table'.
long maxSplitSize = 1024L; long maxSplitSize = 1024L;
htd.setMaxFileSize(maxSplitSize); htd.setMaxFileSize(maxSplitSize);
// Set flush size to 1/4. IncreasingToUpperBoundRegionSplitPolicy // Set flush size to 1/8. IncreasingToUpperBoundRegionSplitPolicy
// grows by the square of the number of regions times flushsize each time. // grows by the cube of the number of regions times flushsize each time.
long flushSize = maxSplitSize/4; long flushSize = maxSplitSize/8;
conf.setLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, flushSize); conf.setLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, flushSize);
htd.setMemStoreFlushSize(flushSize); htd.setMemStoreFlushSize(flushSize);
// If RegionServerService with no regions in it -- 'online regions' == 0 -- // If RegionServerService with no regions in it -- 'online regions' == 0 --
@ -101,18 +101,18 @@ public class TestRegionSplitPolicy {
// Now test that we increase our split size as online regions for a table // Now test that we increase our split size as online regions for a table
// grows. With one region, split size should be flushsize. // grows. With one region, split size should be flushsize.
regions.add(mockRegion); regions.add(mockRegion);
Mockito.doReturn(flushSize/2).when(mockStore).getSize(); Mockito.doReturn(flushSize).when(mockStore).getSize();
// Should not split since store is 1/2 flush size. // Should not split since store is flush size.
assertFalse(policy.shouldSplit()); assertFalse(policy.shouldSplit());
// Set size of store to be > flush size and we should split // Set size of store to be > 2*flush size and we should split
Mockito.doReturn(flushSize + 1).when(mockStore).getSize(); Mockito.doReturn(flushSize*2 + 1).when(mockStore).getSize();
assertTrue(policy.shouldSplit()); assertTrue(policy.shouldSplit());
// Add another region to the 'online regions' on this server and we should // Add another region to the 'online regions' on this server and we should
// now be no longer be splittable since split size has gone up. // now be no longer be splittable since split size has gone up.
regions.add(mockRegion); regions.add(mockRegion);
assertFalse(policy.shouldSplit()); assertFalse(policy.shouldSplit());
// Quadruple (2 squared) the store size and make sure its just over; verify it'll split // Quadruple (2 squared) the store size and make sure its just over; verify it'll split
Mockito.doReturn((flushSize * 2 * 2) + 1).when(mockStore).getSize(); Mockito.doReturn((flushSize * 2 * 2 * 2) + 1).when(mockStore).getSize();
assertTrue(policy.shouldSplit()); assertTrue(policy.shouldSplit());
// Finally assert that even if loads of regions, we'll split at max size // Finally assert that even if loads of regions, we'll split at max size