001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.master.balancer; 019 020import static org.junit.Assert.assertNull; 021import static org.junit.Assert.assertTrue; 022 023import java.time.Duration; 024import java.util.List; 025import java.util.Map; 026import org.apache.hadoop.hbase.HBaseConfiguration; 027import org.apache.hadoop.hbase.ServerName; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.client.RegionInfo; 030import org.apache.hadoop.hbase.master.RackManager; 031import org.apache.hadoop.hbase.master.RegionPlan; 032import org.apache.hadoop.net.DNSToSwitchMapping; 033import org.junit.BeforeClass; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037public class StochasticBalancerTestBase extends BalancerTestBase { 038 039 private static final Logger LOG = LoggerFactory.getLogger(StochasticBalancerTestBase.class); 040 private static final Duration MAX_MAX_RUN_TIME = Duration.ofSeconds(60); 041 042 protected static StochasticLoadBalancer loadBalancer; 043 044 protected static DummyMetricsStochasticBalancer dummyMetricsStochasticBalancer = 045 new DummyMetricsStochasticBalancer(); 046 047 @BeforeClass 048 public static void beforeAllTests() throws Exception { 049 conf = HBaseConfiguration.create(); 050 conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class); 051 conf.setFloat("hbase.master.balancer.stochastic.localityCost", 0); 052 conf.setBoolean("hbase.master.balancer.stochastic.runMaxSteps", true); 053 conf.setLong(StochasticLoadBalancer.MAX_RUNNING_TIME_KEY, 250); 054 loadBalancer = new StochasticLoadBalancer(dummyMetricsStochasticBalancer); 055 loadBalancer.setClusterInfoProvider(new DummyClusterInfoProvider(conf)); 056 loadBalancer.initialize(); 057 } 058 059 protected void setMaxRunTime(Duration maxRunTime) { 060 conf.setLong(StochasticLoadBalancer.MAX_RUNNING_TIME_KEY, maxRunTime.toMillis()); 061 loadBalancer.loadConf(conf); 062 } 063 064 protected void testWithClusterWithIteration(int numNodes, int numRegions, int numRegionsPerServer, 065 int replication, int numTables, boolean assertFullyBalanced, 066 boolean assertFullyBalancedForReplicas) { 067 Map<ServerName, List<RegionInfo>> serverMap = 068 createServerMap(numNodes, numRegions, numRegionsPerServer, replication, numTables); 069 testWithClusterWithIteration(serverMap, null, assertFullyBalanced, 070 assertFullyBalancedForReplicas); 071 } 072 073 protected void increaseMaxRunTimeOrFail() { 074 Duration current = getCurrentMaxRunTime(); 075 assertTrue(current.toMillis() < MAX_MAX_RUN_TIME.toMillis()); 076 Duration newMax = Duration.ofMillis(current.toMillis() * 2); 077 if (newMax.toMillis() > MAX_MAX_RUN_TIME.toMillis()) { 078 setMaxRunTime(MAX_MAX_RUN_TIME); 079 } else { 080 setMaxRunTime(newMax); 081 } 082 } 083 084 protected void testWithClusterWithIteration(Map<ServerName, List<RegionInfo>> serverMap, 085 RackManager rackManager, boolean assertFullyBalanced, boolean assertFullyBalancedForReplicas) { 086 List<ServerAndLoad> list = convertToList(serverMap); 087 LOG.info("Mock Cluster : " + printMock(list) + " " + printStats(list)); 088 089 loadBalancer.setRackManager(rackManager); 090 // Run the balancer. 091 Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable = 092 (Map) mockClusterServersWithTables(serverMap); 093 List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable); 094 if (plans == null) { 095 LOG.debug("First plans are null. Trying more balancer time, or will fail"); 096 increaseMaxRunTimeOrFail(); 097 testWithClusterWithIteration(serverMap, rackManager, assertFullyBalanced, 098 assertFullyBalancedForReplicas); 099 return; 100 } 101 102 List<ServerAndLoad> balancedCluster = null; 103 // Run through iteration until done. Otherwise will be killed as test time out 104 while (plans != null && (assertFullyBalanced || assertFullyBalancedForReplicas)) { 105 // Apply the plan to the mock cluster. 106 balancedCluster = reconcile(list, plans, serverMap); 107 108 // Print out the cluster loads to make debugging easier. 109 LOG.info("Mock after balance: " + printMock(balancedCluster)); 110 111 LoadOfAllTable = (Map) mockClusterServersWithTables(serverMap); 112 plans = loadBalancer.balanceCluster(LoadOfAllTable); 113 } 114 115 // Print out the cluster loads to make debugging easier. 116 LOG.info("Mock Final balance: " + printMock(balancedCluster)); 117 118 if (assertFullyBalanced) { 119 assertNull("Given a requirement to be fully balanced, second attempt at plans should " 120 + "produce none.", plans); 121 } 122 if (assertFullyBalancedForReplicas) { 123 assertRegionReplicaPlacement(serverMap, rackManager); 124 } 125 } 126 127 private Duration getCurrentMaxRunTime() { 128 return Duration.ofMillis(conf.getLong(StochasticLoadBalancer.MAX_RUNNING_TIME_KEY, 129 StochasticLoadBalancer.DEFAULT_MAX_RUNNING_TIME)); 130 } 131}