Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
* The class that creates a load balancer from a conf.
*/
@InterfaceAudience.Private
public class LoadBalancerFactory {
public final class LoadBalancerFactory {

private LoadBalancerFactory() {
}

/**
* The default {@link LoadBalancer} class.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class HeterogeneousCostRulesTestHelper {

private static final Logger LOG = LoggerFactory.getLogger(HeterogeneousCostRulesTestHelper.class);

static final String DEFAULT_RULES_FILE_NAME = "hbase-balancer.rules";

private HeterogeneousCostRulesTestHelper() {
}

/**
* Create rule file with the given rules.
* @param file Name of file to write rules into.
* @return Full file name of the rules file which is <code>dir</code> + DEFAULT_RULES_FILE_NAME.
*/
static String createRulesFile(String file, final List<String> rules) throws IOException {
cleanup(file);
Path path = Files.createFile(FileSystems.getDefault().getPath(file));
return Files.write(path, rules, StandardCharsets.UTF_8).toString();
}

/**
* Create rule file with empty rules.
* @param file Name of file to write rules into.
* @return Full file name of the rules file which is <code>dir</code> + DEFAULT_RULES_FILE_NAME.
*/
static String createRulesFile(String file) throws IOException {
return createRulesFile(file, Collections.emptyList());
}

static void cleanup(String file) throws IOException {
try {
Files.delete(FileSystems.getDefault().getPath(file));
} catch (NoSuchFileException nsfe) {
LOG.warn("FileNotFoundException for {}", file, nsfe);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ public class LoadBalancerPerformanceEvaluation extends AbstractHBaseTool {

// Non-default configurations.
private void setupConf() {
conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, loadBalancerClazz, LoadBalancer.class);
conf.setClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, loadBalancerClazz,
LoadBalancer.class);
loadBalancer = LoadBalancerFactory.getLoadBalancer(conf);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
/*
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* 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 static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
import static org.apache.hadoop.hbase.master.balancer.HeterogeneousCostRulesTestHelper.DEFAULT_RULES_FILE_NAME;
import static org.apache.hadoop.hbase.master.balancer.HeterogeneousCostRulesTestHelper.createRulesFile;
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.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
Expand All @@ -30,7 +35,7 @@
import java.util.concurrent.ThreadLocalRandom;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HBaseCommonTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.client.RegionInfo;
Expand All @@ -48,14 +53,15 @@

@Category({ MasterTests.class, MediumTests.class })
public class TestStochasticLoadBalancerHeterogeneousCost extends StochasticBalancerTestBase {

@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestStochasticLoadBalancerHeterogeneousCost.class);
HBaseClassTestRule.forClass(TestStochasticLoadBalancerHeterogeneousCost.class);

private static final Logger LOG =
LoggerFactory.getLogger(TestStochasticLoadBalancerHeterogeneousCost.class);
LoggerFactory.getLogger(TestStochasticLoadBalancerHeterogeneousCost.class);
private static final double ALLOWED_WINDOW = 1.20;
private static final HBaseTestingUtility HTU = new HBaseTestingUtility();
private static final HBaseCommonTestingUtility HTU = new HBaseCommonTestingUtility();
private static String RULES_FILE;

@BeforeClass
Expand All @@ -69,10 +75,8 @@ public static void beforeAllTests() throws IOException {
HeterogeneousRegionCountCostFunction.class.getName());
// Need to ensure test dir has been created.
assertTrue(FileSystem.get(HTU.getConfiguration()).mkdirs(HTU.getDataTestDir()));
RULES_FILE = HTU.getDataTestDir(
TestStochasticLoadBalancerHeterogeneousCostRules.DEFAULT_RULES_FILE_NAME).toString();
conf.set(
HeterogeneousRegionCountCostFunction.HBASE_MASTER_BALANCER_HETEROGENEOUS_RULES_FILE,
RULES_FILE = HTU.getDataTestDir(DEFAULT_RULES_FILE_NAME).toString();
conf.set(HeterogeneousRegionCountCostFunction.HBASE_MASTER_BALANCER_HETEROGENEOUS_RULES_FILE,
RULES_FILE);
loadBalancer = new StochasticLoadBalancer();
loadBalancer.setClusterInfoProvider(new DummyClusterInfoProvider(conf));
Expand Down Expand Up @@ -146,36 +150,37 @@ public void testOverloaded() throws IOException {
final int numRegions = 120;
final int numRegionsPerServer = 60;

TestStochasticLoadBalancerHeterogeneousCostRules.createRulesFile(RULES_FILE);
createRulesFile(RULES_FILE);
final Map<ServerName, List<RegionInfo>> serverMap =
this.createServerMap(numNodes, numRegions, numRegionsPerServer, 1, 1);
this.createServerMap(numNodes, numRegions, numRegionsPerServer, 1, 1);
final List<RegionPlan> plans =
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
// As we disabled all the other cost functions, balancing only according to
// the heterogeneous cost function should return nothing.
assertNull(plans);
}

private void testHeterogeneousWithCluster(final int numNodes, final int numRegions,
final int numRegionsPerServer, final List<String> rules) throws IOException {
final int numRegionsPerServer, final List<String> rules) throws IOException {

TestStochasticLoadBalancerHeterogeneousCostRules.createRulesFile(RULES_FILE, rules);
createRulesFile(RULES_FILE, rules);
final Map<ServerName, List<RegionInfo>> serverMap =
this.createServerMap(numNodes, numRegions, numRegionsPerServer, 1, 1);
this.createServerMap(numNodes, numRegions, numRegionsPerServer, 1, 1);
this.testWithCluster(serverMap, null, true, false);
}

@Override
protected void testWithCluster(final Map<ServerName, List<RegionInfo>> serverMap,
final RackManager rackManager, final boolean assertFullyBalanced,
final boolean assertFullyBalancedForReplicas) {
final RackManager rackManager, final boolean assertFullyBalanced,
final boolean assertFullyBalancedForReplicas) {
final List<ServerAndLoad> list = this.convertToList(serverMap);
LOG.info("Mock Cluster : " + this.printMock(list) + " " + this.printStats(list));

loadBalancer.setRackManager(rackManager);

// Run the balancer.
final List<RegionPlan> plans =
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
assertNotNull(plans);

// Check to see that this actually got to a stable place.
Expand All @@ -188,16 +193,15 @@ protected void testWithCluster(final Map<ServerName, List<RegionInfo>> serverMap

if (assertFullyBalanced) {
final List<RegionPlan> secondPlans =
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
loadBalancer.balanceTable(HConstants.ENSEMBLE_TABLE_NAME, serverMap);
assertNull(secondPlans);

// create external cost function to retrieve limit
// for each RS
final HeterogeneousRegionCountCostFunction cf =
new HeterogeneousRegionCountCostFunction(conf);
new HeterogeneousRegionCountCostFunction(conf);
assertNotNull(cf);
BalancerClusterState cluster =
new BalancerClusterState(serverMap, null, null, null);
BalancerClusterState cluster = new BalancerClusterState(serverMap, null, null, null);
cf.prepare(cluster);

// checking that we all hosts have a number of regions below their limit
Expand All @@ -212,10 +216,9 @@ protected void testWithCluster(final Map<ServerName, List<RegionInfo>> serverMap

// as the balancer is stochastic, we cannot check exactly the result of the balancing,
// hence the allowedWindow parameter
assertTrue("Host " + sn.getHostname() + " should be below "
+ cf.overallUsage * ALLOWED_WINDOW * 100 + "%; " + cf.overallUsage +
", " + usage + ", " + numberRegions + ", " + limit,
usage <= cf.overallUsage * ALLOWED_WINDOW);
assertTrue("Host " + sn.getHostname() + " should be below " +
cf.overallUsage * ALLOWED_WINDOW * 100 + "%; " + cf.overallUsage + ", " + usage + ", " +
numberRegions + ", " + limit, usage <= cf.overallUsage * ALLOWED_WINDOW);
}
}

Expand All @@ -227,7 +230,7 @@ protected void testWithCluster(final Map<ServerName, List<RegionInfo>> serverMap

@Override
protected Map<ServerName, List<RegionInfo>> createServerMap(int numNodes, int numRegions,
int numRegionsPerServer, int replication, int numTables) {
int numRegionsPerServer, int replication, int numTables) {
// construct a cluster of numNodes, having a total of numRegions. Each RS will hold
// numRegionsPerServer many regions except for the last one, which will host all the
// remaining regions
Expand All @@ -254,7 +257,7 @@ protected Map<ServerName, List<RegionInfo>> createServerMap(int numNodes, int nu

@Override
protected TreeMap<ServerName, List<RegionInfo>> mockClusterServers(int[] mockCluster,
int numTables) {
int numTables) {
int numServers = mockCluster.length;
TreeMap<ServerName, List<RegionInfo>> servers = new TreeMap<>();
for (int i = 0; i < numServers; i++) {
Expand All @@ -266,7 +269,7 @@ protected TreeMap<ServerName, List<RegionInfo>> mockClusterServers(int[] mockClu
return servers;
}

private Queue<ServerName> serverQueue = new LinkedList<>();
private Queue<ServerName> serverQueue = new ArrayDeque<>();

private ServerAndLoad createServer(final String host) {
if (!this.serverQueue.isEmpty()) {
Expand All @@ -280,12 +283,11 @@ private ServerAndLoad createServer(final String host) {
return new ServerAndLoad(sn, 0);
}

static class FairRandomCandidateGenerator extends
RandomCandidateGenerator {
static class FairRandomCandidateGenerator extends RandomCandidateGenerator {

@Override
public BalanceAction pickRandomRegions(BalancerClusterState cluster,
int thisServer, int otherServer) {
public BalanceAction pickRandomRegions(BalancerClusterState cluster, int thisServer,
int otherServer) {
if (thisServer < 0 || otherServer < 0) {
return BalanceAction.NULL_ACTION;
}
Expand All @@ -301,4 +303,4 @@ BalanceAction generate(BalancerClusterState cluster) {
return super.generate(cluster);
}
}
}
}
Loading