diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java index 000e331..4d11abd 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer.java @@ -515,48 +515,6 @@ public class TestStochasticLoadBalancer extends BalancerTestBase { } @Test (timeout = 800000) - public void testRegionReplicasOnMidCluster() { - conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); - conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); - conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000); // 90 sec - loadBalancer.setConf(conf); - int numNodes = 200; - int numRegions = 40 * 200; - int replication = 3; // 3 replicas per region - int numRegionsPerServer = 30; //all regions are mostly balanced - int numTables = 10; - testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true); - } - - @Test (timeout = 800000) - public void testRegionReplicasOnLargeCluster() { - conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); - conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); - conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000); // 90 sec - loadBalancer.setConf(conf); - int numNodes = 1000; - int numRegions = 20 * numNodes; // 20 * replication regions per RS - int numRegionsPerServer = 19; // all servers except one - int numTables = 100; - int replication = 3; - testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true); - } - - @Test (timeout = 800000) - public void testRegionReplicasOnMidClusterHighReplication() { - conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 4000000L); - conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 120 * 1000); // 120 sec - conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); - loadBalancer.setConf(conf); - int numNodes = 80; - int numRegions = 6 * numNodes; - int replication = 80; // 80 replicas per region, one for each server - int numRegionsPerServer = 5; - int numTables = 10; - testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, false, true); - } - - @Test (timeout = 800000) public void testRegionReplicationOnMidClusterSameHosts() { conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000); // 90 sec @@ -621,20 +579,6 @@ public class TestStochasticLoadBalancer extends BalancerTestBase { testWithCluster(serverMap, rm, false, true); } - @Test (timeout = 800000) - public void testRegionReplicationOnMidClusterReplicationGreaterThanNumNodes() { - conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); - conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 120 * 1000); // 120 sec - conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); - loadBalancer.setConf(conf); - int numNodes = 40; - int numRegions = 6 * 50; - int replication = 50; // 50 replicas per region, more than numNodes - int numRegionsPerServer = 6; - int numTables = 10; - testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, false); - } - protected void testWithCluster(int numNodes, int numRegions, int numRegionsPerServer, diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer2.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer2.java new file mode 100644 index 0000000..c62e492 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/balancer/TestStochasticLoadBalancer2.java @@ -0,0 +1,275 @@ +/** + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Queue; +import java.util.TreeMap; + +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.HBaseConfiguration; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.RegionLoad; +import org.apache.hadoop.hbase.ServerLoad; +import org.apache.hadoop.hbase.ServerName; +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.master.balancer.BaseLoadBalancer.Cluster; +import org.apache.hadoop.hbase.testclassification.FlakeyTests; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.net.DNSToSwitchMapping; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({FlakeyTests.class, MediumTests.class}) +public class TestStochasticLoadBalancer2 extends BalancerTestBase { + public static final String REGION_KEY = "testRegion"; + private static StochasticLoadBalancer loadBalancer; + private static final Log LOG = LogFactory.getLog(TestStochasticLoadBalancer.class); + private static Configuration conf; + + @BeforeClass + public static void beforeAllTests() throws Exception { + conf = HBaseConfiguration.create(); + conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class); + conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 0.75f); + conf.setFloat("hbase.regions.slop", 0.0f); + loadBalancer = new StochasticLoadBalancer(); + loadBalancer.setConf(conf); + } + + 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 }; + + // int[testnum][servernumber] -> numregions + 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}, + // 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}, + largeCluster, + + }; + + @Test (timeout = 800000) + public void testRegionReplicasOnMidCluster() { + conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); + conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); + conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000); // 90 sec + loadBalancer.setConf(conf); + int numNodes = 200; + int numRegions = 40 * 200; + int replication = 3; // 3 replicas per region + int numRegionsPerServer = 30; //all regions are mostly balanced + int numTables = 10; + testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true); + } + + @Test (timeout = 800000) + public void testRegionReplicasOnLargeCluster() { + conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); + conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); + conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 90 * 1000); // 90 sec + loadBalancer.setConf(conf); + int numNodes = 1000; + int numRegions = 20 * numNodes; // 20 * replication regions per RS + int numRegionsPerServer = 19; // all servers except one + int numTables = 100; + int replication = 3; + testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, true); + } + + @Test (timeout = 800000) + public void testRegionReplicasOnMidClusterHighReplication() { + conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 4000000L); + conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 120 * 1000); // 120 sec + conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); + loadBalancer.setConf(conf); + int numNodes = 80; + int numRegions = 6 * numNodes; + int replication = 80; // 80 replicas per region, one for each server + int numRegionsPerServer = 5; + int numTables = 10; + testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, false, true); + } + + @Test (timeout = 800000) + public void testRegionReplicationOnMidClusterReplicationGreaterThanNumNodes() { + conf.setLong(StochasticLoadBalancer.MAX_STEPS_KEY, 2000000L); + conf.setLong("hbase.master.balancer.stochastic.maxRunningTime", 120 * 1000); // 120 sec + conf.setFloat("hbase.master.balancer.stochastic.maxMovePercent", 1.0f); + loadBalancer.setConf(conf); + int numNodes = 40; + int numRegions = 6 * 50; + int replication = 50; // 50 replicas per region, more than numNodes + int numRegionsPerServer = 6; + int numTables = 10; + testWithCluster(numNodes, numRegions, numRegionsPerServer, replication, numTables, true, false); + } + + protected void testWithCluster(int numNodes, + int numRegions, + int numRegionsPerServer, + int replication, + int numTables, + boolean assertFullyBalanced, boolean assertFullyBalancedForReplicas) { + Map> serverMap = + createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables); + testWithCluster(serverMap, null, assertFullyBalanced, assertFullyBalancedForReplicas); + } + + + protected void testWithCluster(Map> serverMap, + RackManager rackManager, boolean assertFullyBalanced, boolean assertFullyBalancedForReplicas) { + List list = convertToList(serverMap); + LOG.info("Mock Cluster : " + printMock(list) + " " + printStats(list)); + + loadBalancer.setRackManager(rackManager); + // Run the balancer. + List plans = loadBalancer.balanceCluster(serverMap); + assertNotNull(plans); + + // Check to see that this actually got to a stable place. + if (assertFullyBalanced || assertFullyBalancedForReplicas) { + // Apply the plan to the mock cluster. + List balancedCluster = reconcile(list, plans, serverMap); + + // Print out the cluster loads to make debugging easier. + LOG.info("Mock Balance : " + printMock(balancedCluster)); + + if (assertFullyBalanced) { + assertClusterAsBalanced(balancedCluster); + List secondPlans = loadBalancer.balanceCluster(serverMap); + assertNull(secondPlans); + } + + if (assertFullyBalancedForReplicas) { + assertRegionReplicaPlacement(serverMap, rackManager); + } + } + } + + private Map> createServerMap(int numNodes, + int numRegions, + 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 + int[] cluster = new int[numNodes]; + for (int i =0; i < numNodes; i++) { + cluster[i] = numRegionsPerServer; + } + cluster[cluster.length - 1] = numRegions - ((cluster.length - 1) * numRegionsPerServer); + Map> clusterState = mockClusterServers(cluster, numTables); + if (replication > 0) { + // replicate the regions to the same servers + for (List regions : clusterState.values()) { + int length = regions.size(); + for (int i = 0; i < length; i++) { + for (int r = 1; r < replication ; r++) { + regions.add(RegionReplicaUtil.getRegionInfoForReplica(regions.get(i), r)); + } + } + } + } + + return clusterState; + } +}