diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java index 01540b77090..129fa7a18e5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/LoadBalancer.java @@ -44,7 +44,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; *

On cluster startup, bulk assignment can be used to determine * locations for all Regions in a cluster. * - *

This classes produces plans for the + *

This class produces plans for the * {@link org.apache.hadoop.hbase.master.AssignmentManager} * to execute. */ @@ -52,7 +52,7 @@ import edu.umd.cs.findbugs.annotations.Nullable; public interface LoadBalancer extends Configurable, Stoppable, ConfigurationObserver { // 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 diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java index 196e693a986..641037526f9 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java @@ -62,11 +62,9 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; /** - * The base class for load balancers. It provides the the functions used to by - * {@link org.apache.hadoop.hbase.master.AssignmentManager} to assign regions - * in the edge cases. It doesn't provide an implementation of the - * actual balancing algorithm. - * + * The base class for load balancers. It provides functions used by + * {@link org.apache.hadoop.hbase.master.AssignmentManager} to assign regions in the edge cases. + * It doesn't provide an implementation of the actual balancing algorithm. */ public abstract class BaseLoadBalancer implements LoadBalancer { protected static final int MIN_SERVER_BALANCE = 2; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java index f93449c57ad..de4a2504642 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -37,37 +36,17 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; -import com.google.protobuf.Service; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.HColumnDescriptor; 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.TableDescriptors; 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.master.RackManager; 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.zookeeper.MetaTableLocator; -import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.apache.hadoop.net.DNSToSwitchMapping; import org.junit.Assert; import org.junit.BeforeClass; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java new file mode 100644 index 00000000000..f174438de1d --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/LoadBalancerPerformanceEvaluation.java @@ -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 servers; + private List regions; + private Map regionServerMap; + private Map> 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); + } +} diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java index 751adc56374..c43b94fb0f5 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBaseLoadBalancer.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.stream.Collectors; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -392,11 +393,7 @@ public class TestBaseLoadBalancer extends BalancerTestBase { } private List getListOfServerNames(final List sals) { - List list = new ArrayList<>(); - for (ServerAndLoad e : sals) { - list.add(e.getServerName()); - } - return list; + return sals.stream().map(ServerAndLoad::getServerName).collect(Collectors.toList()); } /** diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestFavoredStochasticLoadBalancer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestFavoredStochasticLoadBalancer.java index 31385675a50..ca4337e6fb6 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestFavoredStochasticLoadBalancer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestFavoredStochasticLoadBalancer.java @@ -33,7 +33,6 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.ClusterStatus; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants;