Skip to content

Commit be8a9a5

Browse files
d-c-manningapurtell
authored andcommitted
HBASE-26989 TestStochasticLoadBalancer fixes for performance and consistency (#4385)
Signed-off-by: Andrew Purtell <[email protected]> Reviewed by: Rushabh Shah <[email protected]> Conflicts: hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java
1 parent 1a5b1b2 commit be8a9a5

File tree

1 file changed

+104
-136
lines changed

1 file changed

+104
-136
lines changed

hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java

Lines changed: 104 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
import org.apache.hadoop.hbase.testclassification.MediumTests;
4949
import org.apache.hadoop.hbase.util.Bytes;
5050
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
51+
import org.junit.Before;
52+
import org.junit.BeforeClass;
5153
import org.junit.ClassRule;
5254
import org.junit.Test;
5355
import org.junit.experimental.categories.Category;
@@ -65,6 +67,18 @@ public class TestStochasticLoadBalancer extends BalancerTestBase {
6567

6668
// Mapping of locality test -> expected locality
6769
private float[] expectedLocalities = { 1.0f, 0.0f, 0.50f, 0.25f, 1.0f };
70+
private static Configuration storedConfiguration;
71+
72+
@BeforeClass
73+
public static void saveInitialConfiguration() {
74+
storedConfiguration = new Configuration(conf);
75+
}
76+
77+
@Before
78+
public void beforeEachTest() {
79+
conf = new Configuration(storedConfiguration);
80+
loadBalancer.onConfigurationChange(conf);
81+
}
6882

6983
/**
7084
* Data set for testLocalityCost: [test][0][0] = mapping of server to number of regions it hosts
@@ -160,142 +174,107 @@ public void testUpdateBalancerLoadInfo() {
160174
BalancerClusterState clusterState = mockCluster(cluster);
161175
Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable =
162176
(Map) mockClusterServersWithTables(servers);
163-
try {
164-
boolean[] perTableBalancerConfigs = { true, false };
165-
for (boolean isByTable : perTableBalancerConfigs) {
166-
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable);
167-
loadBalancer.onConfigurationChange(conf);
168-
dummyMetricsStochasticBalancer.clearDummyMetrics();
169-
loadBalancer.updateBalancerLoadInfo(LoadOfAllTable);
170-
assertTrue("Metrics should be recorded!",
171-
dummyMetricsStochasticBalancer.getDummyCostsMap() != null
172-
&& !dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
173-
174-
String metricRecordKey;
175-
if (isByTable) {
176-
metricRecordKey = "table1#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME;
177-
} else {
178-
metricRecordKey = HConstants.ENSEMBLE_TABLE_NAME + "#"
179-
+ StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME;
180-
}
181-
double curOverallCost = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
182-
double curOverallCostInMetrics =
183-
dummyMetricsStochasticBalancer.getDummyCostsMap().get(metricRecordKey);
184-
assertEquals(curOverallCost, curOverallCostInMetrics, 0.001);
185-
}
186-
} finally {
187-
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
177+
boolean[] perTableBalancerConfigs = { true, false };
178+
for (boolean isByTable : perTableBalancerConfigs) {
179+
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable);
188180
loadBalancer.onConfigurationChange(conf);
181+
dummyMetricsStochasticBalancer.clearDummyMetrics();
182+
loadBalancer.updateBalancerLoadInfo(LoadOfAllTable);
183+
assertTrue("Metrics should be recorded!",
184+
dummyMetricsStochasticBalancer.getDummyCostsMap() != null
185+
&& !dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
186+
187+
String metricRecordKey;
188+
if (isByTable) {
189+
metricRecordKey = "table1#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME;
190+
} else {
191+
metricRecordKey =
192+
HConstants.ENSEMBLE_TABLE_NAME + "#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME;
193+
}
194+
double curOverallCost = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
195+
double curOverallCostInMetrics =
196+
dummyMetricsStochasticBalancer.getDummyCostsMap().get(metricRecordKey);
197+
assertEquals(curOverallCost, curOverallCostInMetrics, 0.001);
189198
}
190199
}
191200

192201
@Test
193202
public void testUpdateStochasticCosts() {
194-
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f);
195-
try {
196-
int[] cluster = new int[] { 10, 0 };
197-
Map<ServerName, List<RegionInfo>> servers = mockClusterServers(cluster);
198-
BalancerClusterState clusterState = mockCluster(cluster);
199-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
200-
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, false);
201-
loadBalancer.onConfigurationChange(conf);
202-
dummyMetricsStochasticBalancer.clearDummyMetrics();
203-
List<RegionPlan> plans =
204-
loadBalancer.balanceCluster((Map) mockClusterServersWithTables(servers));
205-
206-
assertTrue("Balance plan should not be empty!", plans != null && !plans.isEmpty());
207-
assertTrue("There should be metrics record in MetricsStochasticBalancer",
208-
!dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
209-
210-
double overallCostOfCluster = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
211-
double overallCostInMetrics = dummyMetricsStochasticBalancer.getDummyCostsMap().get(
212-
HConstants.ENSEMBLE_TABLE_NAME + "#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME);
213-
assertEquals(overallCostOfCluster, overallCostInMetrics, 0.001);
214-
} finally {
215-
// reset config
216-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
217-
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
218-
loadBalancer.onConfigurationChange(conf);
219-
}
203+
int[] cluster = new int[] { 10, 0 };
204+
Map<ServerName, List<RegionInfo>> servers = mockClusterServers(cluster);
205+
BalancerClusterState clusterState = mockCluster(cluster);
206+
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
207+
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, false);
208+
loadBalancer.onConfigurationChange(conf);
209+
dummyMetricsStochasticBalancer.clearDummyMetrics();
210+
List<RegionPlan> plans =
211+
loadBalancer.balanceCluster((Map) mockClusterServersWithTables(servers));
212+
213+
assertTrue("Balance plan should not be empty!", plans != null && !plans.isEmpty());
214+
assertTrue("There should be metrics record in MetricsStochasticBalancer",
215+
!dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
216+
217+
double overallCostOfCluster = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
218+
double overallCostInMetrics = dummyMetricsStochasticBalancer.getDummyCostsMap().get(
219+
HConstants.ENSEMBLE_TABLE_NAME + "#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME);
220+
assertEquals(overallCostOfCluster, overallCostInMetrics, 0.001);
220221
}
221222

222223
@Test
223224
public void testUpdateStochasticCostsIfBalanceNotRan() {
224-
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f);
225-
try {
226-
int[] cluster = new int[] { 10, 10 };
227-
Map<ServerName, List<RegionInfo>> servers = mockClusterServers(cluster);
228-
BalancerClusterState clusterState = mockCluster(cluster);
229-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", Float.MAX_VALUE);
230-
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, false);
231-
loadBalancer.onConfigurationChange(conf);
232-
dummyMetricsStochasticBalancer.clearDummyMetrics();
233-
List<RegionPlan> plans =
234-
loadBalancer.balanceCluster((Map) mockClusterServersWithTables(servers));
235-
236-
assertTrue("Balance plan should be empty!", plans == null || plans.isEmpty());
237-
assertTrue("There should be metrics record in MetricsStochasticBalancer!",
238-
!dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
239-
240-
double overallCostOfCluster = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
241-
double overallCostInMetrics = dummyMetricsStochasticBalancer.getDummyCostsMap().get(
242-
HConstants.ENSEMBLE_TABLE_NAME + "#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME);
243-
assertEquals(overallCostOfCluster, overallCostInMetrics, 0.001);
244-
} finally {
245-
// reset config
246-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
247-
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
248-
loadBalancer.onConfigurationChange(conf);
249-
}
225+
int[] cluster = new int[] { 10, 10 };
226+
Map<ServerName, List<RegionInfo>> servers = mockClusterServers(cluster);
227+
BalancerClusterState clusterState = mockCluster(cluster);
228+
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", Float.MAX_VALUE);
229+
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, false);
230+
loadBalancer.onConfigurationChange(conf);
231+
dummyMetricsStochasticBalancer.clearDummyMetrics();
232+
List<RegionPlan> plans =
233+
loadBalancer.balanceCluster((Map) mockClusterServersWithTables(servers));
234+
235+
assertTrue("Balance plan should be empty!", plans == null || plans.isEmpty());
236+
assertTrue("There should be metrics record in MetricsStochasticBalancer!",
237+
!dummyMetricsStochasticBalancer.getDummyCostsMap().isEmpty());
238+
239+
double overallCostOfCluster = loadBalancer.computeCost(clusterState, Double.MAX_VALUE);
240+
double overallCostInMetrics = dummyMetricsStochasticBalancer.getDummyCostsMap().get(
241+
HConstants.ENSEMBLE_TABLE_NAME + "#" + StochasticLoadBalancer.OVERALL_COST_FUNCTION_NAME);
242+
assertEquals(overallCostOfCluster, overallCostInMetrics, 0.001);
250243
}
251244

252245
@Test
253246
public void testNeedBalance() {
254-
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.05f);
255-
float slop = conf.getFloat(HConstants.LOAD_BALANCER_SLOP_KEY, 0.2f);
256247
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
257248
conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, -1f);
258-
try {
259-
// Test with/without per table balancer.
260-
boolean[] perTableBalancerConfigs = { true, false };
261-
for (boolean isByTable : perTableBalancerConfigs) {
262-
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable);
263-
loadBalancer.onConfigurationChange(conf);
264-
265-
for (int[] mockCluster : clusterStateMocks) {
266-
assertTrue(hasEmptyBalancerPlans(mockCluster) || needsBalanceIdleRegion(mockCluster));
267-
}
268-
}
269-
} finally {
270-
// reset config
271-
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
272-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
273-
conf.setFloat(HConstants.LOAD_BALANCER_SLOP_KEY, slop);
249+
conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", false);
250+
conf.setLong("hbase.master.balancer.stochastic.maxSteps", 5000L);
251+
// Test with/without per table balancer.
252+
boolean[] perTableBalancerConfigs = { true, false };
253+
for (boolean isByTable : perTableBalancerConfigs) {
254+
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, isByTable);
274255
loadBalancer.onConfigurationChange(conf);
256+
for (int[] mockCluster : clusterStateMocks) {
257+
assertTrue(hasEmptyBalancerPlans(mockCluster) || needsBalanceIdleRegion(mockCluster));
258+
}
275259
}
276260
}
277261

278262
@Test
279263
public void testBalanceOfSloppyServers() {
280-
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.025f);
281-
try {
282-
// We are testing slop checks, so don't "accidentally" balance due to a minCost calculation.
283-
// During development, imbalance of a 100 server cluster, with one node having 10 regions
284-
// and the rest having 5, is 0.0048. With minCostNeedBalance default of 0.025, test should
285-
// validate slop checks without this override. We override just to ensure we will always
286-
// validate slop check here, and for small clusters as well.
287-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
288-
loadBalancer.onConfigurationChange(conf);
289-
for (int[] mockCluster : clusterStateMocksWithNoSlop) {
290-
assertTrue(hasEmptyBalancerPlans(mockCluster));
291-
}
292-
for (int[] mockCluster : clusterStateMocksWithSlop) {
293-
assertFalse(hasEmptyBalancerPlans(mockCluster));
294-
}
295-
} finally {
296-
// reset config
297-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
298-
loadBalancer.onConfigurationChange(conf);
264+
// We are testing slop checks, so don't "accidentally" balance due to a minCost calculation.
265+
// During development, imbalance of a 100 server cluster, with one node having 10 regions
266+
// and the rest having 5, is 0.0048. With minCostNeedBalance default of 0.025, test should
267+
// validate slop checks without this override. We override just to ensure we will always
268+
// validate slop check here, and for small clusters as well.
269+
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
270+
conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", false);
271+
conf.setLong("hbase.master.balancer.stochastic.maxSteps", 5000L);
272+
loadBalancer.onConfigurationChange(conf);
273+
for (int[] mockCluster : clusterStateMocksWithNoSlop) {
274+
assertTrue(hasEmptyBalancerPlans(mockCluster));
275+
}
276+
for (int[] mockCluster : clusterStateMocksWithSlop) {
277+
assertFalse(hasEmptyBalancerPlans(mockCluster));
299278
}
300279
}
301280

@@ -306,17 +285,12 @@ public void testSloppyTablesLoadBalanceByTable() {
306285
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 },
307286
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,
308287
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }, };
309-
float minCost = conf.getFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 0.025f);
310-
try {
311-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
312-
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, true);
313-
loadBalancer.onConfigurationChange(conf);
314-
assertFalse(hasEmptyBalancerPlans(regionsPerServerPerTable));
315-
} finally {
316-
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", minCost);
317-
conf.unset(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE);
318-
loadBalancer.onConfigurationChange(conf);
319-
}
288+
conf.setFloat("hbase.master.balancer.stochastic.minCostNeedBalance", 1.0f);
289+
conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", false);
290+
conf.setLong("hbase.master.balancer.stochastic.maxSteps", 5000L);
291+
conf.setBoolean(HConstants.HBASE_MASTER_LOADBALANCE_BYTABLE, true);
292+
loadBalancer.onConfigurationChange(conf);
293+
assertFalse(hasEmptyBalancerPlans(regionsPerServerPerTable));
320294
}
321295

322296
private boolean hasEmptyBalancerPlans(int[] mockCluster) {
@@ -439,7 +413,6 @@ public void testSkewCost() {
439413
@Test
440414
public void testCostAfterUndoAction() {
441415
final int runs = 10;
442-
loadBalancer.onConfigurationChange(conf);
443416
for (int[] mockCluster : clusterStateMocks) {
444417
BalancerClusterState cluster = mockCluster(mockCluster);
445418
loadBalancer.initCosts(cluster);
@@ -542,17 +515,12 @@ public void testLosingRs() throws Exception {
542515

543516
@Test
544517
public void testAdditionalCostFunction() {
545-
try {
546-
conf.set(StochasticLoadBalancer.COST_FUNCTIONS_COST_FUNCTIONS_KEY,
547-
DummyCostFunction.class.getName());
518+
conf.set(StochasticLoadBalancer.COST_FUNCTIONS_COST_FUNCTIONS_KEY,
519+
DummyCostFunction.class.getName());
548520

549-
loadBalancer.onConfigurationChange(conf);
550-
assertTrue(Arrays.asList(loadBalancer.getCostFunctionNames())
551-
.contains(DummyCostFunction.class.getSimpleName()));
552-
} finally {
553-
conf.unset(StochasticLoadBalancer.COST_FUNCTIONS_COST_FUNCTIONS_KEY);
554-
loadBalancer.onConfigurationChange(conf);
555-
}
521+
loadBalancer.onConfigurationChange(conf);
522+
assertTrue(Arrays.asList(loadBalancer.getCostFunctionNames())
523+
.contains(DummyCostFunction.class.getSimpleName()));
556524
}
557525

558526
@Test

0 commit comments

Comments
 (0)