You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2022/04/28 19:28:21 UTC
[hbase] branch master updated: HBASE-22349 slop in StochasticLoadBalancer (#4371)
This is an automated email from the ASF dual-hosted git repository.
apurtell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/master by this push:
new f848c61e3d2 HBASE-22349 slop in StochasticLoadBalancer (#4371)
f848c61e3d2 is described below
commit f848c61e3d27017d78d6244bdb4c95373ba451c6
Author: d-c-manning <67...@users.noreply.github.com>
AuthorDate: Thu Apr 28 12:28:15 2022 -0700
HBASE-22349 slop in StochasticLoadBalancer (#4371)
Signed-off-by: Andrew Purtell <ap...@apache.org>
---
.../hbase/master/balancer/BaseLoadBalancer.java | 35 ++--
.../hbase/master/balancer/SimpleLoadBalancer.java | 17 +-
.../master/balancer/StochasticLoadBalancer.java | 11 +-
.../hbase/master/balancer/BalancerTestBase.java | 198 +++++++++++++--------
.../balancer/StochasticBalancerTestBase.java | 1 -
.../master/balancer/TestSimpleLoadBalancer.java | 33 ++--
.../balancer/TestStochasticLoadBalancer.java | 73 +++++++-
hbase-common/src/main/resources/hbase-default.xml | 19 +-
.../master/balancer/TestBalancerDecision.java | 3 +
9 files changed, 254 insertions(+), 136 deletions(-)
diff --git a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java
index ac5ef44bed0..e453d11fd31 100644
--- a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java
+++ b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java
@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
@@ -139,6 +140,28 @@ public abstract class BaseLoadBalancer implements LoadBalancer {
return isServerExistsWithMoreRegions && isServerExistsWithZeroRegions;
}
+ protected final boolean sloppyRegionServerExist(ClusterLoadState cs) {
+ if (slop < 0) {
+ LOG.debug("Slop is less than zero, not checking for sloppiness.");
+ return false;
+ }
+ float average = cs.getLoadAverage(); // for logging
+ int floor = (int) Math.floor(average * (1 - slop));
+ int ceiling = (int) Math.ceil(average * (1 + slop));
+ if (!(cs.getMaxLoad() > ceiling || cs.getMinLoad() < floor)) {
+ NavigableMap<ServerAndLoad, List<RegionInfo>> serversByLoad = cs.getServersByLoad();
+ if (LOG.isTraceEnabled()) {
+ // If nothing to balance, then don't say anything unless trace-level logging.
+ LOG.trace("Skipping load balancing because balanced cluster; " + "servers=" +
+ cs.getNumServers() + " regions=" + cs.getNumRegions() + " average=" + average +
+ " mostloaded=" + serversByLoad.lastKey().getLoad() + " leastloaded=" +
+ serversByLoad.firstKey().getLoad());
+ }
+ return false;
+ }
+ return true;
+ }
+
/**
* Generates a bulk assignment plan to be used on cluster startup using a
* simple round-robin assignment.
@@ -372,16 +395,6 @@ public abstract class BaseLoadBalancer implements LoadBalancer {
return Collections.unmodifiableMap(assignments);
}
- protected final float normalizeSlop(float slop) {
- if (slop < 0) {
- return 0;
- }
- if (slop > 1) {
- return 1;
- }
- return slop;
- }
-
protected float getDefaultSlop() {
return 0.2f;
}
@@ -394,7 +407,7 @@ public abstract class BaseLoadBalancer implements LoadBalancer {
}
protected void loadConf(Configuration conf) {
- this.slop = normalizeSlop(conf.getFloat("hbase.regions.slop", getDefaultSlop()));
+ this.slop = conf.getFloat("hbase.regions.slop", getDefaultSlop());
this.rackManager = new RackManager(conf);
useRegionFinder = conf.getBoolean("hbase.master.balancer.uselocality", true);
if (useRegionFinder) {
diff --git a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
index 84418b36f61..91cfffaeb51 100644
--- a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
+++ b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java
@@ -191,24 +191,9 @@ public class SimpleLoadBalancer extends BaseLoadBalancer {
if (idleRegionServerExist(c)) {
return true;
}
-
// Check if we even need to do any load balancing
// HBASE-3681 check sloppiness first
- float average = cs.getLoadAverage(); // for logging
- int floor = (int) Math.floor(average * (1 - slop));
- int ceiling = (int) Math.ceil(average * (1 + slop));
- if (!(cs.getMaxLoad() > ceiling || cs.getMinLoad() < floor)) {
- NavigableMap<ServerAndLoad, List<RegionInfo>> serversByLoad = cs.getServersByLoad();
- if (LOG.isTraceEnabled()) {
- // If nothing to balance, then don't say anything unless trace-level logging.
- LOG.trace("Skipping load balancing because balanced cluster; " + "servers=" +
- cs.getNumServers() + " regions=" + cs.getNumRegions() + " average=" + average +
- " mostloaded=" + serversByLoad.lastKey().getLoad() + " leastloaded=" +
- serversByLoad.firstKey().getLoad());
- }
- return false;
- }
- return true;
+ return sloppyRegionServerExist(cs);
}
/**
diff --git a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
index ff6d031cef3..b3754715992 100644
--- a/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
+++ b/hbase-balancer/src/main/java/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.java
@@ -203,11 +203,6 @@ public class StochasticLoadBalancer extends BaseLoadBalancer {
return this.candidateGenerators;
}
- @Override
- protected float getDefaultSlop() {
- return 0.001f;
- }
-
protected List<CandidateGenerator> createCandidateGenerators() {
List<CandidateGenerator> candidateGenerators = new ArrayList<CandidateGenerator>(4);
candidateGenerators.add(GeneratorType.RANDOM.ordinal(), new RandomCandidateGenerator());
@@ -357,6 +352,12 @@ public class StochasticLoadBalancer extends BaseLoadBalancer {
return true;
}
+ if (sloppyRegionServerExist(cs)) {
+ LOG.info("Running balancer because cluster has sloppy server(s)."+
+ " function cost={}", functionCost());
+ return true;
+ }
+
double total = 0.0;
for (CostFunction c : costFunctions) {
if (!c.isNeeded()) {
diff --git a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java
index 59335079bcd..5fa69c4fd9b 100644
--- a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java
+++ b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/BalancerTestBase.java
@@ -60,83 +60,122 @@ public class BalancerTestBase {
protected static Configuration conf;
protected int[] largeCluster = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 };
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 };
// int[testnum][servernumber] -> numregions
protected int[][] clusterStateMocks = new int[][]{
- // 1 node
- new int[]{0},
- new int[]{1},
- new int[]{10},
- // 2 node
- new int[]{0, 0},
- new int[]{2, 0},
- new int[]{2, 1},
- new int[]{2, 2},
- new int[]{2, 3},
- new int[]{2, 4},
- new int[]{1, 1},
- new int[]{0, 1},
- new int[]{10, 1},
- new int[]{514, 1432},
- new int[]{48, 53},
- // 3 node
- new int[]{0, 1, 2},
- new int[]{1, 2, 3},
- new int[]{0, 2, 2},
- new int[]{0, 3, 0},
- new int[]{0, 4, 0},
- new int[]{20, 20, 0},
- // 4 node
- new int[]{0, 1, 2, 3},
- new int[]{4, 0, 0, 0},
- new int[]{5, 0, 0, 0},
- new int[]{6, 6, 0, 0},
- new int[]{6, 2, 0, 0},
- new int[]{6, 1, 0, 0},
- new int[]{6, 0, 0, 0},
- new int[]{4, 4, 4, 7},
- new int[]{4, 4, 4, 8},
- new int[]{0, 0, 0, 7},
- // 5 node
- new int[]{1, 1, 1, 1, 4},
- // 6 nodes
- new int[]{1500, 500, 500, 500, 10, 0},
- new int[]{1500, 500, 500, 500, 500, 0},
- // more nodes
- new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
- new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
- new int[]{6, 6, 5, 6, 6, 6, 6, 6, 6, 1},
- new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 54},
- new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 55},
- new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 56},
- new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 16},
- new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 8},
- new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 9},
- new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 10},
- new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 123},
- new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 155},
- new int[]{10, 7, 12, 8, 11, 10, 9, 14},
- new int[]{13, 14, 6, 10, 10, 10, 8, 10},
- new int[]{130, 14, 60, 10, 100, 10, 80, 10},
- new int[]{130, 140, 60, 100, 100, 100, 80, 100},
- new int[]{0, 5 , 5, 5, 5},
- largeCluster,
+ // 1 node
+ new int[]{0},
+ new int[]{1},
+ new int[]{10},
+ // 2 node
+ new int[]{0, 0},
+ new int[]{2, 0},
+ new int[]{2, 1},
+ new int[]{2, 2},
+ new int[]{2, 3},
+ new int[]{2, 4},
+ new int[]{1, 1},
+ new int[]{0, 1},
+ new int[]{10, 1},
+ new int[]{514, 1432},
+ new int[]{48, 53},
+ // 3 node
+ new int[]{0, 1, 2},
+ new int[]{1, 2, 3},
+ new int[]{0, 2, 2},
+ new int[]{0, 3, 0},
+ new int[]{0, 4, 0},
+ new int[]{20, 20, 0},
+ // 4 node
+ new int[]{0, 1, 2, 3},
+ new int[]{4, 0, 0, 0},
+ new int[]{5, 0, 0, 0},
+ new int[]{6, 6, 0, 0},
+ new int[]{6, 2, 0, 0},
+ new int[]{6, 1, 0, 0},
+ new int[]{6, 0, 0, 0},
+ new int[]{4, 4, 4, 7},
+ new int[]{4, 4, 4, 8},
+ new int[]{0, 0, 0, 7},
+ // 5 node
+ new int[]{1, 1, 1, 1, 4},
+ // 6 nodes
+ new int[]{1500, 500, 500, 500, 10, 0},
+ new int[]{1500, 500, 500, 500, 500, 0},
+ // more nodes
+ new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
+ new int[]{6, 6, 5, 6, 6, 6, 6, 6, 6, 1},
+ new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 54},
+ new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 55},
+ new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 56},
+ new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 16},
+ new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 8},
+ new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 9},
+ new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 10},
+ new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 123},
+ new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 155},
+ new int[]{10, 7, 12, 8, 11, 10, 9, 14},
+ new int[]{13, 14, 6, 10, 10, 10, 8, 10},
+ new int[]{130, 14, 60, 10, 100, 10, 80, 10},
+ new int[]{130, 140, 60, 100, 100, 100, 80, 100},
+ new int[]{0, 5 , 5, 5, 5},
+ largeCluster,
};
+ // int[testnum][servernumber] -> numregions
+ protected int[][] clusterStateMocksWithNoSlop = new int[][] {
+ // 1 node
+ new int[]{0},
+ new int[]{1},
+ new int[]{10},
+ // 2 node
+ new int[]{0, 0},
+ new int[]{2, 1},
+ new int[]{2, 2},
+ new int[]{2, 3},
+ new int[]{1, 1},
+ new int[]{80, 120},
+ new int[]{1428, 1432},
+ // more nodes
+ new int[]{100, 90, 120, 90, 110, 100, 90, 120},
+ };
+
+ // int[testnum][servernumber] -> numregions
+ protected int[][] clusterStateMocksWithSlop = new int[][] {
+ // 2 node
+ new int[]{1, 4},
+ new int[]{10, 20},
+ new int[]{80, 123},
+ // more nodes
+ new int[]{100, 100, 100, 100, 100, 100, 100, 100, 100, 200},
+ new int[] {
+ 10, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ },
+ };
// This class is introduced because IP to rack resolution can be lengthy.
public static class MockMapping implements DNSToSwitchMapping {
@@ -351,6 +390,23 @@ public class BalancerTestBase {
map.put(sn, sal);
}
+ protected TreeMap<ServerName, List<RegionInfo>> mockClusterServers(int[][] mockCluster) {
+ // dimension1: table, dimension2: regions per server
+ int numTables = mockCluster.length;
+ TreeMap<ServerName, List<RegionInfo>> servers = new TreeMap<>();
+ for (int i = 0; i < numTables; i++) {
+ TableName tableName = TableName.valueOf("table" + i);
+ for (int j = 0; j < mockCluster[i].length; j++) {
+ ServerName serverName = ServerName.valueOf("server" + j, 1000, -1);
+ int numRegions = mockCluster[i][j];
+ List<RegionInfo> regions = createRegions(numRegions, tableName);
+ servers.putIfAbsent(serverName, new ArrayList<>());
+ servers.get(serverName).addAll(regions);
+ }
+ }
+ return servers;
+ }
+
protected TreeMap<ServerName, List<RegionInfo>> mockClusterServers(int[] mockCluster) {
return mockClusterServers(mockCluster, -1);
}
diff --git a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/StochasticBalancerTestBase.java b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/StochasticBalancerTestBase.java
index 8a077b793cc..71d6f8d8699 100644
--- a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/StochasticBalancerTestBase.java
+++ b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/StochasticBalancerTestBase.java
@@ -46,7 +46,6 @@ public class StochasticBalancerTestBase extends BalancerTestBase {
public static void beforeAllTests() throws Exception {
conf = HBaseConfiguration.create();
conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class);
- conf.setFloat("hbase.regions.slop", 0.0f);
conf.setFloat("hbase.master.balancer.stochastic.localityCost", 0);
conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", true);
loadBalancer = new StochasticLoadBalancer(dummyMetricsStochasticBalancer);
diff --git a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestSimpleLoadBalancer.java b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestSimpleLoadBalancer.java
index 1fb02629255..5d2abdd8fb6 100644
--- a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestSimpleLoadBalancer.java
+++ b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestSimpleLoadBalancer.java
@@ -165,28 +165,19 @@ public class TestSimpleLoadBalancer extends BalancerTestBase {
}
@Test
- public void testBalanceClusterOverallStrictly() throws Exception {
- int[] regionNumOfTable1PerServer = { 3, 3, 4, 4, 4, 4, 5, 5, 5 };
- int[] regionNumOfTable2PerServer = { 2, 2, 2, 2, 2, 2, 2, 2, 1 };
- TreeMap<ServerName, List<RegionInfo>> serverRegionInfo = new TreeMap<>();
- List<ServerAndLoad> serverAndLoads = new ArrayList<>();
- for (int i = 0; i < regionNumOfTable1PerServer.length; i++) {
- ServerName serverName = ServerName.valueOf("server" + i, 1000, -1);
- List<RegionInfo> regions1 =
- createRegions(regionNumOfTable1PerServer[i], TableName.valueOf("table1"));
- List<RegionInfo> regions2 =
- createRegions(regionNumOfTable2PerServer[i], TableName.valueOf("table2"));
- regions1.addAll(regions2);
- serverRegionInfo.put(serverName, regions1);
- ServerAndLoad serverAndLoad = new ServerAndLoad(serverName,
- regionNumOfTable1PerServer[i] + regionNumOfTable2PerServer[i]);
- serverAndLoads.add(serverAndLoad);
- }
- HashMap<TableName, TreeMap<ServerName, List<RegionInfo>>> LoadOfAllTable =
+ public void testBalanceClusterOverallStrictly() {
+ int[][] regionsPerServerPerTable = new int[][]{
+ new int[]{ 3, 3, 4, 4, 4, 4, 5, 5, 5 },
+ new int[]{ 2, 2, 2, 2, 2, 2, 2, 2, 1 },
+ };
+ TreeMap<ServerName, List<RegionInfo>> serverRegionInfo =
+ mockClusterServers(regionsPerServerPerTable);
+ List<ServerAndLoad> serverAndLoads = convertToList(serverRegionInfo);
+ Map<TableName, TreeMap<ServerName, List<RegionInfo>>> loadOfAllTable =
mockClusterServersWithTables(serverRegionInfo);
- loadBalancer.setClusterLoad((Map) LoadOfAllTable);
- List<RegionPlan> partialplans = loadBalancer.balanceTable(TableName.valueOf("table1"),
- LoadOfAllTable.get(TableName.valueOf("table1")));
+ loadBalancer.setClusterLoad((Map) loadOfAllTable);
+ List<RegionPlan> partialplans = loadBalancer.balanceTable(TableName.valueOf("table0"),
+ loadOfAllTable.get(TableName.valueOf("table0")));
List<ServerAndLoad> balancedServerLoads =
reconcile(serverAndLoads, partialplans, serverRegionInfo);
for (ServerAndLoad serverAndLoad : balancedServerLoads) {
diff --git a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
index 2f862cda65f..9cb47043704 100644
--- a/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
+++ b/hbase-balancer/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.master.balancer;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -327,7 +328,9 @@ public class TestStochasticLoadBalancer extends StochasticBalancerTestBase {
@Test
public void testNeedBalance() {
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f);
+ float slop = conf.getFloat(HConstants.LOAD_BALANCER_SLOP_KEY, 0.2f);
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
+ conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, -1f);
try {
// Test with/without per table balancer.
boolean[] perTableBalancerConfigs = {true, false};
@@ -335,22 +338,80 @@ public class TestStochasticLoadBalancer extends StochasticBalancerTestBase {
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable);
loadBalancer.onConfigurationChange(conf);
for (int[] mockCluster : clusterStateMocks) {
- Map<ServerName, List<RegionInfo>> servers = mockClusterServers(mockCluster);
- Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable =
- (Map) mockClusterServersWithTables(servers);
- List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable);
- boolean emptyPlans = plans == null || plans.isEmpty();
- assertTrue(emptyPlans || needsBalanceIdleRegion(mockCluster));
+ assertTrue(hasEmptyBalancerPlans(mockCluster) || needsBalanceIdleRegion(mockCluster));
}
}
} finally {
// reset config
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
+ conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, slop);
loadBalancer.onConfigurationChange(conf);
}
}
+ @Test
+ public void testBalanceOfSloppyServers() {
+ float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.025f);
+ try {
+ // We are testing slop checks, so don't "accidentally" balance due to a minCost calculation.
+ // During development, imbalance of a 100 server cluster, with one node having 10 regions
+ // and the rest having 5, is 0.0048. With minCostNeedBalance default of 0.025, test should
+ // validate slop checks without this override. We override just to ensure we will always
+ // validate slop check here, and for small clusters as well.
+ conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
+ loadBalancer.onConfigurationChange(conf);
+ for (int[] mockCluster : clusterStateMocksWithNoSlop) {
+ assertTrue(hasEmptyBalancerPlans(mockCluster));
+ }
+ for (int[] mockCluster : clusterStateMocksWithSlop) {
+ assertFalse(hasEmptyBalancerPlans(mockCluster));
+ }
+ } finally {
+ // reset config
+ conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
+ loadBalancer.onConfigurationChange(conf);
+ }
+ }
+
+ @Test
+ public void testSloppyTablesLoadBalanceByTable() {
+ int[][] regionsPerServerPerTable = new int[][] {
+ new int[] { 8, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
+ new int[] { 2, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ , 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
+ };
+ float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.025f);
+ try {
+ conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
+ conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, true);
+ loadBalancer.onConfigurationChange(conf);
+ assertFalse(hasEmptyBalancerPlans(regionsPerServerPerTable));
+ } finally {
+ conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
+ conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
+ loadBalancer.onConfigurationChange(conf);
+ }
+ }
+
+ private boolean hasEmptyBalancerPlans(int[] mockCluster) {
+ Map<ServerName, List<RegionInfo>> servers = mockClusterServers(mockCluster);
+ return hasEmptyBalancerPlans(servers);
+ }
+
+ private boolean hasEmptyBalancerPlans(int[][] mockCluster) {
+ Map<ServerName, List<RegionInfo>> servers = mockClusterServers(mockCluster);
+ return hasEmptyBalancerPlans(servers);
+ }
+
+ private boolean hasEmptyBalancerPlans(Map<ServerName, List<RegionInfo>> servers) {
+ Map<TableName, Map<ServerName, List<RegionInfo>>> loadOfAllTable =
+ (Map) mockClusterServersWithTables(servers);
+ List<RegionPlan> plans = loadBalancer.balanceCluster(loadOfAllTable);
+ return plans == null || plans.isEmpty();
+ }
+
@Test
public void testLocalityCost() throws Exception {
Configuration conf = HBaseConfiguration.create();
diff --git a/hbase-common/src/main/resources/hbase-default.xml b/hbase-common/src/main/resources/hbase-default.xml
index 628b1e2fece..67ad1f3e9e3 100644
--- a/hbase-common/src/main/resources/hbase-default.xml
+++ b/hbase-common/src/main/resources/hbase-default.xml
@@ -618,11 +618,20 @@ possible configurations would overwhelm and obscure the important.
</property>
<property>
<name>hbase.regions.slop</name>
- <value>0.001</value>
- <description>Rebalance if any regionserver has average + (average * slop) regions.
- The default value of this parameter is 0.001 in StochasticLoadBalancer (the default load
- balancer), while the default is 0.2 in other load balancers (i.e.,
- SimpleLoadBalancer).</description>
+ <value>0.2</value>
+ <description>The load balancer can trigger for several reasons. This value controls one of
+ those reasons. Run the balancer if any regionserver has a region count outside the range of
+ average +/- (average * slop) regions.
+ If the value of slop is negative, disable sloppiness checks. The balancer can still run for
+ other reasons, but sloppiness will not be one of them.
+ If the value of slop is 0, run the balancer if any server has a region count more than 1
+ from the average.
+ If the value of slop is 100, run the balancer if any server has a region count greater than
+ 101 times the average.
+ The default value of this parameter is 0.2, which runs the balancer if any server has a region
+ count less than 80% of the average, or greater than 120% of the average.
+ Note that for the default StochasticLoadBalancer, this does not guarantee any balancing
+ actions will be taken, but only that the balancer will attempt to run.</description>
</property>
<property>
<name>hbase.normalizer.period</name>
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBalancerDecision.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBalancerDecision.java
index f7e1110283d..a1eb2528458 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBalancerDecision.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestBalancerDecision.java
@@ -65,7 +65,9 @@ public class TestBalancerDecision extends StochasticBalancerTestBase {
loadBalancer.setClusterInfoProvider(provider);
loadBalancer.onConfigurationChange(conf);
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f);
+ float slop = conf.getFloat(HConstants.LOAD_BALANCER_SLOP_KEY, 0.2f);
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
+ conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, -1f);
try {
// Test with/without per table balancer.
boolean[] perTableBalancerConfigs = {true, false};
@@ -100,6 +102,7 @@ public class TestBalancerDecision extends StochasticBalancerTestBase {
// reset config
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
+ conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, slop);
loadBalancer.onConfigurationChange(conf);
}
}