HBASE-17786 Create LoadBalancer perf-test tool to benchmark Load Balancer algorithm performance

Signed-off-by: Michael Stack <stack@apache.org>
Signed-off-by: Sean Busbey <busbey@apache.org>
This commit is contained in:
Umesh Agashe 2017-05-03 16:34:13 -07:00 committed by Sean Busbey
parent b34ab5980e
commit da68537ae6
6 changed files with 187 additions and 34 deletions

View File

@ -44,7 +44,7 @@ import edu.umd.cs.findbugs.annotations.Nullable;
* <p>On cluster startup, bulk assignment can be used to determine * <p>On cluster startup, bulk assignment can be used to determine
* locations for all Regions in a cluster. * locations for all Regions in a cluster.
* *
* <p>This classes produces plans for the * <p>This class produces plans for the
* {@link org.apache.hadoop.hbase.master.AssignmentManager} * {@link org.apache.hadoop.hbase.master.AssignmentManager}
* to execute. * to execute.
*/ */
@ -52,7 +52,7 @@ import edu.umd.cs.findbugs.annotations.Nullable;
public interface LoadBalancer extends Configurable, Stoppable, ConfigurationObserver { public interface LoadBalancer extends Configurable, Stoppable, ConfigurationObserver {
// Used to signal to the caller that the region(s) cannot be assigned // Used to signal to the caller that the region(s) cannot be assigned
static final ServerName BOGUS_SERVER_NAME = ServerName.valueOf("bogus.example.com,1,1"); ServerName BOGUS_SERVER_NAME = ServerName.valueOf("bogus.example.com,1,1");
/** /**
* Set the current cluster status. This allows a LoadBalancer to map host name to a server * Set the current cluster status. This allows a LoadBalancer to map host name to a server

View File

@ -62,11 +62,9 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
/** /**
* The base class for load balancers. It provides the the functions used to by * The base class for load balancers. It provides functions used by
* {@link org.apache.hadoop.hbase.master.AssignmentManager} to assign regions * {@link org.apache.hadoop.hbase.master.AssignmentManager} to assign regions in the edge cases.
* in the edge cases. It doesn't provide an implementation of the * It doesn't provide an implementation of the actual balancing algorithm.
* actual balancing algorithm.
*
*/ */
public abstract class BaseLoadBalancer implements LoadBalancer { public abstract class BaseLoadBalancer implements LoadBalancer {
protected static final int MIN_SERVER_BALANCE = 2; protected static final int MIN_SERVER_BALANCE = 2;

View File

@ -21,7 +21,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -37,37 +36,17 @@ import java.util.SortedSet;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import com.google.protobuf.Service;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ChoreService;
import org.apache.hadoop.hbase.CoordinatedStateManager;
import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.ProcedureInfo;
import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableDescriptors;
import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotDisabledException;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.client.ClusterConnection;
import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.RegionReplicaUtil;
import org.apache.hadoop.hbase.master.RackManager; import org.apache.hadoop.hbase.master.RackManager;
import org.apache.hadoop.hbase.master.RegionPlan; import org.apache.hadoop.hbase.master.RegionPlan;
import org.apache.hadoop.hbase.executor.ExecutorService;
import org.apache.hadoop.hbase.master.*;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
import org.apache.hadoop.hbase.quotas.MasterQuotaManager;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.hadoop.net.DNSToSwitchMapping; import org.apache.hadoop.net.DNSToSwitchMapping;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;

View File

@ -0,0 +1,180 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.master.balancer;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.HBaseCommonTestingUtility;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.master.LoadBalancer;
import org.apache.hadoop.hbase.util.AbstractHBaseTool;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Tool to test performance of different {@link org.apache.hadoop.hbase.master.LoadBalancer}
* implementations.
* Example command:
* $ bin/hbase org.apache.hadoop.hbase.master.balancer.LoadBalancerPerformanceEvaluation
* -regions 1000 -servers 100
* -load_balancer org.apache.hadoop.hbase.master.balancer.SimpleLoadBalancer
*/
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
public class LoadBalancerPerformanceEvaluation extends AbstractHBaseTool {
private static final Log LOG =
LogFactory.getLog(LoadBalancerPerformanceEvaluation.class.getName());
protected static final HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility();
private static final int DEFAULT_NUM_REGIONS = 1000000;
private static Option NUM_REGIONS_OPT = new Option("regions", true,
"Number of regions to consider by load balancer. Default: " + DEFAULT_NUM_REGIONS);
private static final int DEFAULT_NUM_SERVERS = 1000;
private static Option NUM_SERVERS_OPT = new Option("servers", true,
"Number of servers to consider by load balancer. Default: " + DEFAULT_NUM_SERVERS);
private static final String DEFAULT_LOAD_BALANCER =
"org.apache.hadoop.hbase.master.balancer.StochasticLoadBalancer";
private static Option LOAD_BALANCER_OPT = new Option("load_balancer", true,
"Type of Load Balancer to use. Default: " + DEFAULT_LOAD_BALANCER);
private int numRegions;
private int numServers;
private String loadBalancerType;
private Class<?> loadBalancerClazz;
private LoadBalancer loadBalancer;
// data
private List<ServerName> servers;
private List<HRegionInfo> regions;
private Map<HRegionInfo, ServerName> regionServerMap;
private Map<ServerName, List<HRegionInfo>> serverRegionMap;
// Non-default configurations.
private void setupConf() {
conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, loadBalancerClazz, LoadBalancer.class);
loadBalancer = LoadBalancerFactory.getLoadBalancer(conf);
}
private void generateRegionsAndServers() {
// regions
regions = new ArrayList<>(numRegions);
regionServerMap = new HashMap<>(numRegions);
for (int i = 0; i < numRegions; ++i) {
byte[] start = new byte[16];
byte[] end = new byte[16];
Bytes.putInt(start, 0, i);
Bytes.putInt(end, 0, i + 1);
TableName tableName = TableName.valueOf("LoadBalancerPerfTable");
HRegionInfo hri = new HRegionInfo(tableName, start, end, false, i);
regions.add(hri);
regionServerMap.put(hri, null);
}
// servers
servers = new ArrayList<>(numServers);
serverRegionMap = new HashMap<>(numServers);
for (int i = 0; i < numServers; ++i) {
ServerName sn = ServerName.valueOf("srv" + i, HConstants.DEFAULT_REGIONSERVER_PORT, i);
servers.add(sn);
serverRegionMap.put(sn, i == 0 ? regions : Collections.emptyList());
}
}
@Override
protected void addOptions() {
addOption(NUM_REGIONS_OPT);
addOption(NUM_SERVERS_OPT);
addOption(LOAD_BALANCER_OPT);
}
@Override
protected void processOptions(CommandLine cmd) {
numRegions = getOptionAsInt(cmd, NUM_REGIONS_OPT.getOpt(), DEFAULT_NUM_REGIONS);
Preconditions.checkArgument(numRegions > 0, "Invalid number of regions!");
numServers = getOptionAsInt(cmd, NUM_SERVERS_OPT.getOpt(), DEFAULT_NUM_SERVERS);
Preconditions.checkArgument(numServers > 0, "Invalid number of servers!");
loadBalancerType = cmd.getOptionValue(LOAD_BALANCER_OPT.getOpt(), DEFAULT_LOAD_BALANCER);
Preconditions.checkArgument(!loadBalancerType.isEmpty(), "Invalid load balancer type!");
try {
loadBalancerClazz = Class.forName(loadBalancerType);
} catch (ClassNotFoundException e) {
System.err.println("Class '" + loadBalancerType + "' not found!");
System.exit(1);
}
setupConf();
}
private String formatResults(final String methodName, final long timeMillis) {
return String.format("Time for %-25s: %dms%n", methodName, timeMillis);
}
@Override
protected int doWork() throws Exception {
generateRegionsAndServers();
String methodName = "roundRobinAssignment";
LOG.info("Calling " + methodName);
Stopwatch watch = new Stopwatch().start();
loadBalancer.roundRobinAssignment(regions, servers);
System.out.print(formatResults(methodName, watch.elapsedMillis()));
methodName = "retainAssignment";
LOG.info("Calling " + methodName);
watch.reset().start();
loadBalancer.retainAssignment(regionServerMap, servers);
System.out.print(formatResults(methodName, watch.elapsedMillis()));
methodName = "balanceCluster";
LOG.info("Calling " + methodName);
watch.reset().start();
loadBalancer.balanceCluster(serverRegionMap);
System.out.print(formatResults(methodName, watch.elapsedMillis()));
return EXIT_SUCCESS;
}
public static void main(String[] args) throws IOException {
LoadBalancerPerformanceEvaluation tool = new LoadBalancerPerformanceEvaluation();
tool.setConf(UTIL.getConfiguration());
tool.run(args);
}
}

View File

@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -392,11 +393,7 @@ public class TestBaseLoadBalancer extends BalancerTestBase {
} }
private List<ServerName> getListOfServerNames(final List<ServerAndLoad> sals) { private List<ServerName> getListOfServerNames(final List<ServerAndLoad> sals) {
List<ServerName> list = new ArrayList<>(); return sals.stream().map(ServerAndLoad::getServerName).collect(Collectors.toList());
for (ServerAndLoad e : sals) {
list.add(e.getServerName());
}
return list;
} }
/** /**

View File

@ -33,7 +33,6 @@ import java.util.Set;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterStatus;
import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;