HBASE-15463 Region normalizer should check whether split/merge is enabled

This commit is contained in:
tedyu 2016-03-15 09:03:27 -07:00
parent ca816f0780
commit 8fcc1e8e95
4 changed files with 65 additions and 11 deletions

View File

@ -583,6 +583,7 @@ public class HMaster extends HRegionServer implements MasterServices {
this.balancer = LoadBalancerFactory.getLoadBalancer(conf);
this.normalizer = RegionNormalizerFactory.getRegionNormalizer(conf);
this.normalizer.setMasterServices(this);
this.normalizer.setMasterRpcServices((MasterRpcServices)rpcServices);
this.loadBalancerTracker = new LoadBalancerTracker(zooKeeper, this);
this.loadBalancerTracker.start();

View File

@ -24,6 +24,7 @@ import org.apache.hadoop.hbase.HBaseIOException;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.master.MasterRpcServices;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.normalizer.NormalizationPlan.PlanType;
@ -46,6 +47,13 @@ public interface RegionNormalizer {
*/
void setMasterServices(MasterServices masterServices);
/**
* Set the master RPC service. Must be called before first call to
* {@link #computePlanForTable(TableName)}.
* @param masterRpcServices master RPC services to use
*/
void setMasterRpcServices(MasterRpcServices masterRpcServices);
/**
* Computes next optimal normalization plan.
* @param table table to normalize

View File

@ -18,6 +18,8 @@
*/
package org.apache.hadoop.hbase.master.normalizer;
import com.google.protobuf.ServiceException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.HBaseIOException;
@ -26,8 +28,11 @@ import org.apache.hadoop.hbase.RegionLoad;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Admin.MasterSwitchType;
import org.apache.hadoop.hbase.master.MasterRpcServices;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.master.normalizer.NormalizationPlan.PlanType;
import org.apache.hadoop.hbase.protobuf.RequestConverter;
import java.util.ArrayList;
import java.util.Collections;
@ -59,6 +64,7 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
private static final Log LOG = LogFactory.getLog(SimpleRegionNormalizer.class);
private static final int MIN_REGION_COUNT = 3;
private MasterServices masterServices;
private MasterRpcServices masterRpcServices;
private static long[] skippedCount = new long[NormalizationPlan.PlanType.values().length];
/**
@ -70,6 +76,11 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
this.masterServices = masterServices;
}
@Override
public void setMasterRpcServices(MasterRpcServices masterRpcServices) {
this.masterRpcServices = masterRpcServices;
}
@Override
public void planSkipped(HRegionInfo hri, PlanType type) {
skippedCount[type.ordinal()]++;
@ -138,19 +149,35 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
LOG.debug("Table " + table + ", average region size: " + avgRegionSize);
int candidateIdx = 0;
boolean splitEnabled = true, mergeEnabled = true;
try {
splitEnabled = masterRpcServices.isSplitOrMergeEnabled(null,
RequestConverter.buildIsSplitOrMergeEnabledRequest(MasterSwitchType.SPLIT)).getEnabled();
} catch (ServiceException se) {
LOG.debug("Unable to determine whether split is enabled", se);
}
try {
mergeEnabled = masterRpcServices.isSplitOrMergeEnabled(null,
RequestConverter.buildIsSplitOrMergeEnabledRequest(MasterSwitchType.MERGE)).getEnabled();
} catch (ServiceException se) {
LOG.debug("Unable to determine whether split is enabled", se);
}
while (candidateIdx < tableRegions.size()) {
HRegionInfo hri = tableRegions.get(candidateIdx);
long regionSize = getRegionSize(hri);
// if the region is > 2 times larger than average, we split it, split
// is more high priority normalization action than merge.
if (regionSize > 2 * avgRegionSize) {
if (splitEnabled) {
LOG.info("Table " + table + ", large region " + hri.getRegionNameAsString() + " has size "
+ regionSize + ", more than twice avg size, splitting");
plans.add(new SplitNormalizationPlan(hri, null));
}
} else {
if (candidateIdx == tableRegions.size()-1) {
break;
}
if (mergeEnabled) {
HRegionInfo hri2 = tableRegions.get(candidateIdx+1);
long regionSize2 = getRegionSize(hri2);
if (regionSize + regionSize2 < avgRegionSize) {
@ -161,6 +188,7 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
candidateIdx++;
}
}
}
candidateIdx++;
}
if (plans.isEmpty()) {

View File

@ -25,7 +25,11 @@ import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.RegionLoad;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.master.MasterRpcServices;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.protobuf.RequestConverter;
import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledRequest;
import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSplitOrMergeEnabledResponse;
import org.apache.hadoop.hbase.testclassification.MasterTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
import org.apache.hadoop.hbase.util.Bytes;
@ -34,6 +38,9 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mockito;
import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -56,6 +63,7 @@ public class TestSimpleRegionNormalizer {
// mocks
private static MasterServices masterServices;
private static MasterRpcServices masterRpcServices;
@BeforeClass
public static void beforeAllTests() throws Exception {
@ -259,6 +267,7 @@ public class TestSimpleRegionNormalizer {
protected void setupMocksForNormalizer(Map<byte[], Integer> regionSizes,
List<HRegionInfo> hris) {
masterServices = Mockito.mock(MasterServices.class, RETURNS_DEEP_STUBS);
masterRpcServices = Mockito.mock(MasterRpcServices.class, RETURNS_DEEP_STUBS);
// for simplicity all regions are assumed to be on one server; doesn't matter to us
ServerName sn = ServerName.valueOf("localhost", 0, 1L);
@ -275,7 +284,15 @@ public class TestSimpleRegionNormalizer {
when(masterServices.getServerManager().getLoad(sn).
getRegionsLoad().get(region.getKey())).thenReturn(regionLoad);
}
try {
when(masterRpcServices.isSplitOrMergeEnabled(any(RpcController.class),
any(IsSplitOrMergeEnabledRequest.class))).thenReturn(
IsSplitOrMergeEnabledResponse.newBuilder().setEnabled(true).build());
} catch (ServiceException se) {
LOG.debug("error setting isSplitOrMergeEnabled switch", se);
}
normalizer.setMasterServices(masterServices);
normalizer.setMasterRpcServices(masterRpcServices);
}
}