1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.balancer;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.when;
26
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.Queue;
35 import java.util.TreeMap;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.hadoop.conf.Configuration;
40 import org.apache.hadoop.hbase.ClusterStatus;
41 import org.apache.hadoop.hbase.HBaseConfiguration;
42 import org.apache.hadoop.hbase.HRegionInfo;
43 import org.apache.hadoop.hbase.RegionLoad;
44 import org.apache.hadoop.hbase.ServerLoad;
45 import org.apache.hadoop.hbase.ServerName;
46 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
47 import org.apache.hadoop.hbase.master.MockNoopMasterServices;
48 import org.apache.hadoop.hbase.master.RackManager;
49 import org.apache.hadoop.hbase.master.RegionPlan;
50 import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer.Cluster;
51 import org.apache.hadoop.hbase.testclassification.FlakeyTests;
52 import org.apache.hadoop.hbase.testclassification.MediumTests;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.junit.Ignore;
55 import org.junit.Test;
56 import org.junit.experimental.categories.Category;
57
58 @Category({FlakeyTests.class, MediumTests.class})
59 public class TestStochasticLoadBalancer extends BalancerTestBase {
60 public static final String REGION_KEY = "testRegion";
61 private static final Log LOG = LogFactory.getLog(TestStochasticLoadBalancer.class);
62
63 @Test
64 public void testKeepRegionLoad() throws Exception {
65
66 ServerName sn = ServerName.valueOf("test:8080", 100);
67 int numClusterStatusToAdd = 20000;
68 for (int i = 0; i < numClusterStatusToAdd; i++) {
69 ServerLoad sl = mock(ServerLoad.class);
70
71 RegionLoad rl = mock(RegionLoad.class);
72 when(rl.getStores()).thenReturn(i);
73
74 Map<byte[], RegionLoad> regionLoadMap =
75 new TreeMap<byte[], RegionLoad>(Bytes.BYTES_COMPARATOR);
76 regionLoadMap.put(Bytes.toBytes(REGION_KEY), rl);
77 when(sl.getRegionsLoad()).thenReturn(regionLoadMap);
78
79 ClusterStatus clusterStatus = mock(ClusterStatus.class);
80 when(clusterStatus.getServers()).thenReturn(Arrays.asList(sn));
81 when(clusterStatus.getLoad(sn)).thenReturn(sl);
82
83 loadBalancer.setClusterStatus(clusterStatus);
84 }
85 assertTrue(loadBalancer.loads.get(REGION_KEY) != null);
86 assertTrue(loadBalancer.loads.get(REGION_KEY).size() == 15);
87
88 Queue<RegionLoad> loads = loadBalancer.loads.get(REGION_KEY);
89 int i = 0;
90 while(loads.size() > 0) {
91 RegionLoad rl = loads.remove();
92 assertEquals(i + (numClusterStatusToAdd - 15), rl.getStores());
93 i ++;
94 }
95 }
96
97
98
99
100
101
102
103
104
105 @Test
106 public void testBalanceCluster() throws Exception {
107
108 for (int[] mockCluster : clusterStateMocks) {
109 Map<ServerName, List<HRegionInfo>> servers = mockClusterServers(mockCluster);
110 List<ServerAndLoad> list = convertToList(servers);
111 LOG.info("Mock Cluster : " + printMock(list) + " " + printStats(list));
112 List<RegionPlan> plans = loadBalancer.balanceCluster(servers);
113 List<ServerAndLoad> balancedCluster = reconcile(list, plans, servers);
114 LOG.info("Mock Balance : " + printMock(balancedCluster));
115 assertClusterAsBalanced(balancedCluster);
116 List<RegionPlan> secondPlans = loadBalancer.balanceCluster(servers);
117 assertNull(secondPlans);
118 for (Map.Entry<ServerName, List<HRegionInfo>> entry : servers.entrySet()) {
119 returnRegions(entry.getValue());
120 returnServer(entry.getKey());
121 }
122 }
123 }
124
125 @Test
126 public void testLocalityCost() throws Exception {
127 Configuration conf = HBaseConfiguration.create();
128 MockNoopMasterServices master = new MockNoopMasterServices();
129 StochasticLoadBalancer.CostFunction
130 costFunction = new StochasticLoadBalancer.LocalityCostFunction(conf, master);
131
132 for (int[][] clusterRegionLocations : clusterRegionLocationMocks) {
133 MockCluster cluster = new MockCluster(clusterRegionLocations);
134 costFunction.init(cluster);
135 double cost = costFunction.cost();
136
137 assertEquals(0.5f, cost, 0.001);
138 }
139 }
140
141 @Test
142 public void testMoveCost() throws Exception {
143 Configuration conf = HBaseConfiguration.create();
144 StochasticLoadBalancer.CostFunction
145 costFunction = new StochasticLoadBalancer.MoveCostFunction(conf);
146 for (int[] mockCluster : clusterStateMocks) {
147 BaseLoadBalancer.Cluster cluster = mockCluster(mockCluster);
148 costFunction.init(cluster);
149 double cost = costFunction.cost();
150 assertEquals(0.0f, cost, 0.001);
151
152
153 cluster.setNumRegions(200);
154 cluster.setNumMovedRegions(10);
155 cost = costFunction.cost();
156 assertEquals(0.05f, cost, 0.001);
157 cluster.setNumMovedRegions(100);
158 cost = costFunction.cost();
159 assertEquals(0.5f, cost, 0.001);
160 cluster.setNumMovedRegions(200);
161 cost = costFunction.cost();
162 assertEquals(1.0f, cost, 0.001);
163
164
165
166 cluster.setNumRegions(10000);
167 cluster.setNumMovedRegions(250);
168 cost = costFunction.cost();
169 assertEquals(0.1f, cost, 0.001);
170 cluster.setNumMovedRegions(1250);
171 cost = costFunction.cost();
172 assertEquals(0.5f, cost, 0.001);
173 cluster.setNumMovedRegions(2500);
174 cost = costFunction.cost();
175 assertEquals(1.0f, cost, 0.01);
176 }
177 }
178
179 @Test
180 public void testSkewCost() {
181 Configuration conf = HBaseConfiguration.create();
182 StochasticLoadBalancer.CostFunction
183 costFunction = new StochasticLoadBalancer.RegionCountSkewCostFunction(conf);
184 for (int[] mockCluster : clusterStateMocks) {
185 costFunction.init(mockCluster(mockCluster));
186 double cost = costFunction.cost();
187 assertTrue(cost >= 0);
188 assertTrue(cost <= 1.01);
189 }
190
191 costFunction.init(mockCluster(new int[]{0, 0, 0, 0, 1}));
192 assertEquals(0,costFunction.cost(), 0.01);
193 costFunction.init(mockCluster(new int[]{0, 0, 0, 1, 1}));
194 assertEquals(0, costFunction.cost(), 0.01);
195 costFunction.init(mockCluster(new int[]{0, 0, 1, 1, 1}));
196 assertEquals(0, costFunction.cost(), 0.01);
197 costFunction.init(mockCluster(new int[]{0, 1, 1, 1, 1}));
198 assertEquals(0, costFunction.cost(), 0.01);
199 costFunction.init(mockCluster(new int[]{1, 1, 1, 1, 1}));
200 assertEquals(0, costFunction.cost(), 0.01);
201 costFunction.init(mockCluster(new int[]{10000, 0, 0, 0, 0}));
202 assertEquals(1, costFunction.cost(), 0.01);
203 }
204
205 @Test
206 public void testTableSkewCost() {
207 Configuration conf = HBaseConfiguration.create();
208 StochasticLoadBalancer.CostFunction
209 costFunction = new StochasticLoadBalancer.TableSkewCostFunction(conf);
210 for (int[] mockCluster : clusterStateMocks) {
211 BaseLoadBalancer.Cluster cluster = mockCluster(mockCluster);
212 costFunction.init(cluster);
213 double cost = costFunction.cost();
214 assertTrue(cost >= 0);
215 assertTrue(cost <= 1.01);
216 }
217 }
218
219 @Test
220 public void testCostFromArray() {
221 Configuration conf = HBaseConfiguration.create();
222 StochasticLoadBalancer.CostFromRegionLoadFunction
223 costFunction = new StochasticLoadBalancer.MemstoreSizeCostFunction(conf);
224 costFunction.init(mockCluster(new int[]{0, 0, 0, 0, 1}));
225
226 double[] statOne = new double[100];
227 for (int i =0; i < 100; i++) {
228 statOne[i] = 10;
229 }
230 assertEquals(0, costFunction.costFromArray(statOne), 0.01);
231
232 double[] statTwo= new double[101];
233 for (int i =0; i < 100; i++) {
234 statTwo[i] = 0;
235 }
236 statTwo[100] = 100;
237 assertEquals(1, costFunction.costFromArray(statTwo), 0.01);
238
239 double[] statThree = new double[200];
240 for (int i =0; i < 100; i++) {
241 statThree[i] = (0);
242 statThree[i+100] = 100;
243 }
244 assertEquals(0.5, costFunction.costFromArray(statThree), 0.01);
245 }
246
247 @Test(timeout = 60000)
248 public void testLosingRs() throws Exception {
249 int numNodes = 3;
250 int numRegions = 20;
251 int numRegionsPerServer = 3;
252 int replication = 1;
253 int numTables = 2;
254
255 Map<ServerName, List<HRegionInfo>> serverMap =
256 createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables);
257 List<ServerAndLoad> list = convertToList(serverMap);
258
259
260 List<RegionPlan> plans = loadBalancer.balanceCluster(serverMap);
261 assertNotNull(plans);
262
263
264 List<ServerAndLoad> balancedCluster = reconcile(list, plans, serverMap);
265
266 assertClusterAsBalanced(balancedCluster);
267
268 ServerName sn = serverMap.keySet().toArray(new ServerName[serverMap.size()])[0];
269
270 ServerName deadSn = ServerName.valueOf(sn.getHostname(), sn.getPort(), sn.getStartcode() - 100);
271
272 serverMap.put(deadSn, new ArrayList<HRegionInfo>(0));
273
274 plans = loadBalancer.balanceCluster(serverMap);
275 assertNull(plans);
276 }
277
278 @Test
279 public void testReplicaCost() {
280 Configuration conf = HBaseConfiguration.create();
281 StochasticLoadBalancer.CostFunction
282 costFunction = new StochasticLoadBalancer.RegionReplicaHostCostFunction(conf);
283 for (int[] mockCluster : clusterStateMocks) {
284 BaseLoadBalancer.Cluster cluster = mockCluster(mockCluster);
285 costFunction.init(cluster);
286 double cost = costFunction.cost();
287 assertTrue(cost >= 0);
288 assertTrue(cost <= 1.01);
289 }
290 }
291
292 @Test
293 public void testReplicaCostForReplicas() {
294 Configuration conf = HBaseConfiguration.create();
295 StochasticLoadBalancer.CostFunction
296 costFunction = new StochasticLoadBalancer.RegionReplicaHostCostFunction(conf);
297
298 int [] servers = new int[] {3,3,3,3,3};
299 TreeMap<ServerName, List<HRegionInfo>> clusterState = mockClusterServers(servers);
300
301 BaseLoadBalancer.Cluster cluster;
302
303 cluster = new BaseLoadBalancer.Cluster(clusterState, null, null, null);
304 costFunction.init(cluster);
305 double costWithoutReplicas = costFunction.cost();
306 assertEquals(0, costWithoutReplicas, 0);
307
308
309 HRegionInfo replica1 = RegionReplicaUtil.getRegionInfoForReplica(
310 clusterState.firstEntry().getValue().get(0),1);
311 clusterState.lastEntry().getValue().add(replica1);
312
313 cluster = new BaseLoadBalancer.Cluster(clusterState, null, null, null);
314 costFunction.init(cluster);
315 double costWith1ReplicaDifferentServer = costFunction.cost();
316
317 assertEquals(0, costWith1ReplicaDifferentServer, 0);
318
319
320 HRegionInfo replica2 = RegionReplicaUtil.getRegionInfoForReplica(replica1, 2);
321 clusterState.lastEntry().getValue().add(replica2);
322
323 cluster = new BaseLoadBalancer.Cluster(clusterState, null, null, null);
324 costFunction.init(cluster);
325 double costWith1ReplicaSameServer = costFunction.cost();
326
327 assertTrue(costWith1ReplicaDifferentServer < costWith1ReplicaSameServer);
328
329
330
331 HRegionInfo replica3;
332 Iterator<Entry<ServerName, List<HRegionInfo>>> it;
333 Entry<ServerName, List<HRegionInfo>> entry;
334
335 clusterState = mockClusterServers(servers);
336 it = clusterState.entrySet().iterator();
337 entry = it.next();
338 HRegionInfo hri = entry.getValue().get(0);
339 replica1 = RegionReplicaUtil.getRegionInfoForReplica(hri, 1);
340 replica2 = RegionReplicaUtil.getRegionInfoForReplica(hri, 2);
341 replica3 = RegionReplicaUtil.getRegionInfoForReplica(hri, 3);
342 entry.getValue().add(replica1);
343 entry.getValue().add(replica2);
344 it.next().getValue().add(replica3);
345
346 cluster = new BaseLoadBalancer.Cluster(clusterState, null, null, null);
347 costFunction.init(cluster);
348 double costWith3ReplicasSameServer = costFunction.cost();
349
350 clusterState = mockClusterServers(servers);
351 hri = clusterState.firstEntry().getValue().get(0);
352 replica1 = RegionReplicaUtil.getRegionInfoForReplica(hri, 1);
353 replica2 = RegionReplicaUtil.getRegionInfoForReplica(hri, 2);
354 replica3 = RegionReplicaUtil.getRegionInfoForReplica(hri, 3);
355
356 clusterState.firstEntry().getValue().add(replica1);
357 clusterState.lastEntry().getValue().add(replica2);
358 clusterState.lastEntry().getValue().add(replica3);
359
360 cluster = new BaseLoadBalancer.Cluster(clusterState, null, null, null);
361 costFunction.init(cluster);
362 double costWith2ReplicasOnTwoServers = costFunction.cost();
363
364 assertTrue(costWith2ReplicasOnTwoServers < costWith3ReplicasSameServer);
365 }
366
367 @Test
368 public void testNeedsBalanceForColocatedReplicas() {
369
370
371 List<HRegionInfo> regions = randomRegions(1);
372 ServerName s1 = ServerName.valueOf("host1", 1000, 11111);
373 ServerName s2 = ServerName.valueOf("host11", 1000, 11111);
374 Map<ServerName, List<HRegionInfo>> map = new HashMap<ServerName, List<HRegionInfo>>();
375 map.put(s1, regions);
376 regions.add(RegionReplicaUtil.getRegionInfoForReplica(regions.get(0), 1));
377
378 regions = randomRegions(1);
379 map.put(s2, regions);
380 assertTrue(loadBalancer.needsBalance(new Cluster(map, null, null, null)));
381
382
383 map.clear();
384 regions = randomRegions(1);
385 List<HRegionInfo> regionsOnS2 = new ArrayList<HRegionInfo>(1);
386 regionsOnS2.add(RegionReplicaUtil.getRegionInfoForReplica(regions.get(0), 1));
387 map.put(s1, regions);
388 map.put(s2, regionsOnS2);
389
390 map.put(ServerName.valueOf("host2", 1000, 11111), randomRegions(1));
391 assertTrue(loadBalancer.needsBalance(new Cluster(map, null, null,
392 new ForTestRackManagerOne())));
393 }
394
395 @Test (timeout = 60000)
396 public void testSmallCluster() {
397 int numNodes = 10;
398 int numRegions = 1000;
399 int numRegionsPerServer = 40;
400 int replication = 1;
401 int numTables = 10;
402 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
403 }
404
405 @Test (timeout = 60000)
406 public void testSmallCluster2() {
407 int numNodes = 20;
408 int numRegions = 2000;
409 int numRegionsPerServer = 40;
410 int replication = 1;
411 int numTables = 10;
412 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
413 }
414
415 @Test (timeout = 60000)
416 public void testSmallCluster3() {
417 int numNodes = 20;
418 int numRegions = 2000;
419 int numRegionsPerServer = 1;
420 int replication = 1;
421 int numTables = 10;
422
423 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, false, false);
424 }
425
426 @Test (timeout = 800000)
427 public void testMidCluster() {
428 int numNodes = 100;
429 int numRegions = 10000;
430 int numRegionsPerServer = 60;
431 int replication = 1;
432 int numTables = 40;
433 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
434 }
435
436 @Test (timeout = 800000)
437 public void testMidCluster2() {
438 int numNodes = 200;
439 int numRegions = 100000;
440 int numRegionsPerServer = 40;
441 int replication = 1;
442 int numTables = 400;
443 testWithCluster(numNodes,
444 numRegions,
445 numRegionsPerServer,
446 replication,
447 numTables,
448 false,
449 false);
450 }
451
452
453 @Test (timeout = 800000)
454 public void testMidCluster3() {
455 int numNodes = 100;
456 int numRegions = 2000;
457 int numRegionsPerServer = 9;
458 int replication = 1;
459 int numTables = 110;
460 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
461
462 }
463
464 @Test
465 public void testLargeCluster() {
466 int numNodes = 1000;
467 int numRegions = 100000;
468 int numRegionsPerServer = 80;
469 int numTables = 100;
470 int replication = 1;
471 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
472 }
473
474 @Test (timeout = 800000)
475 public void testRegionReplicasOnSmallCluster() {
476 int numNodes = 10;
477 int numRegions = 1000;
478 int replication = 3;
479 int numRegionsPerServer = 80;
480 int numTables = 10;
481 testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true);
482 }
483
484 @Ignore @Test (timeout = 800000)
485 public void testRegionReplicationOnMidClusterSameHosts() {
486 conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L);
487 conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000);
488 conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f);
489 loadBalancer.setConf(conf);
490 int numHosts = 100;
491 int numRegions = 100 * 100;
492 int replication = 3;
493 int numRegionsPerServer = 5;
494 int numTables = 10;
495 Map<ServerName, List<HRegionInfo>> serverMap =
496 createServerMap(numHosts, numRegions, numRegionsPerServer, replication, numTables);
497 int numNodesPerHost = 4;
498
499
500 Map<ServerName, List<HRegionInfo>> newServerMap = new TreeMap<ServerName, List<HRegionInfo>>(serverMap);
501 for (Map.Entry<ServerName, List<HRegionInfo>> entry : serverMap.entrySet()) {
502 for (int i=1; i < numNodesPerHost; i++) {
503 ServerName s1 = entry.getKey();
504 ServerName s2 = ServerName.valueOf(s1.getHostname(), s1.getPort() + i, 1);
505 newServerMap.put(s2, new ArrayList<HRegionInfo>());
506 }
507 }
508
509 testWithCluster(newServerMap, null, true, true);
510 }
511
512 private static class ForTestRackManager extends RackManager {
513 int numRacks;
514 public ForTestRackManager(int numRacks) {
515 this.numRacks = numRacks;
516 }
517 @Override
518 public String getRack(ServerName server) {
519 return "rack_" + (server.hashCode() % numRacks);
520 }
521 }
522
523 private static class ForTestRackManagerOne extends RackManager {
524 @Override
525 public String getRack(ServerName server) {
526 return server.getHostname().endsWith("1") ? "rack1" : "rack2";
527 }
528 }
529
530 @Test (timeout = 800000)
531 public void testRegionReplicationOnMidClusterWithRacks() {
532 conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 10000000L);
533 conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f);
534 conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 120 * 1000);
535 loadBalancer.setConf(conf);
536 int numNodes = 30;
537 int numRegions = numNodes * 30;
538 int replication = 3;
539 int numRegionsPerServer = 28;
540 int numTables = 10;
541 int numRacks = 4;
542 Map<ServerName, List<HRegionInfo>> serverMap =
543 createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables);
544 RackManager rm = new ForTestRackManager(numRacks);
545
546 testWithCluster(serverMap, rm, false, true);
547 }
548
549 }