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; 019 020import static org.junit.jupiter.api.Assertions.assertTrue; 021 022import java.io.IOException; 023import java.util.concurrent.atomic.AtomicBoolean; 024import java.util.concurrent.atomic.AtomicInteger; 025import org.apache.hadoop.hbase.HBaseTestingUtil; 026import org.apache.hadoop.hbase.HConstants; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.client.RegionInfo; 029import org.apache.hadoop.hbase.regionserver.HRegionServer; 030import org.apache.hadoop.hbase.testclassification.MasterTests; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.util.Bytes; 033import org.junit.jupiter.api.AfterEach; 034import org.junit.jupiter.api.BeforeEach; 035import org.junit.jupiter.api.Disabled; 036import org.junit.jupiter.api.Tag; 037import org.junit.jupiter.api.Test; 038 039@Disabled // SimpleLoadBalancer seems borked whether AMv2 or not. Disabling till gets attention. 040@Tag(MasterTests.TAG) 041@Tag(MediumTests.TAG) 042public class TestMasterBalanceThrottling { 043 044 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 045 private static final byte[] FAMILYNAME = Bytes.toBytes("fam"); 046 047 @BeforeEach 048 public void setupConfiguration() { 049 TEST_UTIL.getConfiguration().set(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, 050 "org.apache.hadoop.hbase.master.balancer.SimpleLoadBalancer"); 051 } 052 053 @AfterEach 054 public void shutdown() throws Exception { 055 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_BALANCER_MAX_BALANCING, 056 HConstants.DEFAULT_HBASE_BALANCER_PERIOD); 057 TEST_UTIL.getConfiguration().setDouble(HConstants.HBASE_MASTER_BALANCER_MAX_RIT_PERCENT, 058 HConstants.DEFAULT_HBASE_MASTER_BALANCER_MAX_RIT_PERCENT); 059 TEST_UTIL.shutdownMiniCluster(); 060 } 061 062 @Test 063 public void testThrottlingByBalanceInterval() throws Exception { 064 // Use default config and start a cluster of two regionservers. 065 TEST_UTIL.startMiniCluster(2); 066 067 TableName tableName = createTable("testNoThrottling"); 068 final HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); 069 070 // Default max balancing time is 300000 ms and there are 50 regions to balance 071 // The balance interval is 6000 ms, much longger than the normal region in transition duration 072 // So the master can balance the region one by one 073 unbalance(master, tableName); 074 AtomicInteger maxCount = new AtomicInteger(0); 075 AtomicBoolean stop = new AtomicBoolean(false); 076 Thread checker = startBalancerChecker(master, maxCount, stop); 077 master.balance(); 078 stop.set(true); 079 checker.interrupt(); 080 checker.join(); 081 assertTrue(maxCount.get() == 1, "max regions in transition: " + maxCount.get()); 082 083 TEST_UTIL.deleteTable(tableName); 084 } 085 086 @Test 087 public void testThrottlingByMaxRitPercent() throws Exception { 088 // Set max balancing time to 500 ms and max percent of regions in transition to 0.05 089 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_BALANCER_MAX_BALANCING, 500); 090 TEST_UTIL.getConfiguration().setDouble(HConstants.HBASE_MASTER_BALANCER_MAX_RIT_PERCENT, 0.05); 091 TEST_UTIL.startMiniCluster(2); 092 093 TableName tableName = createTable("testThrottlingByMaxRitPercent"); 094 final HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); 095 096 unbalance(master, tableName); 097 AtomicInteger maxCount = new AtomicInteger(0); 098 AtomicBoolean stop = new AtomicBoolean(false); 099 Thread checker = startBalancerChecker(master, maxCount, stop); 100 master.balance(); 101 stop.set(true); 102 checker.interrupt(); 103 checker.join(); 104 // The max number of regions in transition is 100 * 0.05 = 5 105 assertTrue(maxCount.get() == 5, "max regions in transition: " + maxCount.get()); 106 107 TEST_UTIL.deleteTable(tableName); 108 } 109 110 private TableName createTable(String table) throws IOException { 111 TableName tableName = TableName.valueOf(table); 112 byte[] startKey = new byte[] { 0x00 }; 113 byte[] stopKey = new byte[] { 0x7f }; 114 TEST_UTIL.createTable(tableName, new byte[][] { FAMILYNAME }, 1, startKey, stopKey, 100); 115 return tableName; 116 } 117 118 private Thread startBalancerChecker(final HMaster master, final AtomicInteger maxCount, 119 final AtomicBoolean stop) { 120 Runnable checker = new Runnable() { 121 @Override 122 public void run() { 123 while (!stop.get()) { 124 maxCount.set( 125 Math.max(maxCount.get(), master.getAssignmentManager().getRegionsInTransitionCount())); 126 try { 127 Thread.sleep(10); 128 } catch (InterruptedException e) { 129 e.printStackTrace(); 130 } 131 } 132 } 133 }; 134 Thread thread = new Thread(checker); 135 thread.start(); 136 return thread; 137 } 138 139 private void unbalance(HMaster master, TableName tableName) throws Exception { 140 while (master.getAssignmentManager().getRegionsInTransitionCount() > 0) { 141 Thread.sleep(100); 142 } 143 HRegionServer biasedServer = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0); 144 for (RegionInfo regionInfo : TEST_UTIL.getAdmin().getRegions(tableName)) { 145 master.move(regionInfo.getEncodedNameAsBytes(), 146 Bytes.toBytes(biasedServer.getServerName().getServerName())); 147 } 148 while (master.getAssignmentManager().getRegionsInTransitionCount() > 0) { 149 Thread.sleep(100); 150 } 151 } 152}