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.assertEquals; 021import static org.junit.Assert.assertTrue; 022import static org.mockito.Mockito.mock; 023import static org.mockito.Mockito.when; 024 025import java.io.IOException; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.TreeMap; 032import org.apache.hadoop.conf.Configuration; 033import org.apache.hadoop.hbase.ClusterMetrics; 034import org.apache.hadoop.hbase.HBaseClassTestRule; 035import org.apache.hadoop.hbase.HBaseConfiguration; 036import org.apache.hadoop.hbase.RegionMetrics; 037import org.apache.hadoop.hbase.ServerMetrics; 038import org.apache.hadoop.hbase.ServerName; 039import org.apache.hadoop.hbase.Size; 040import org.apache.hadoop.hbase.TableName; 041import org.apache.hadoop.hbase.client.RegionInfo; 042import org.apache.hadoop.hbase.master.RegionPlan; 043import org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer; 044import org.apache.hadoop.hbase.rsgroup.RSGroupInfo; 045import org.apache.hadoop.hbase.testclassification.LargeTests; 046import org.apache.hadoop.hbase.util.Bytes; 047import org.junit.BeforeClass; 048import org.junit.ClassRule; 049import org.junit.Test; 050import org.junit.experimental.categories.Category; 051 052/** 053 * Test RSGroupBasedLoadBalancer with StochasticLoadBalancer as internal balancer 054 */ 055@Category(LargeTests.class) 056public class TestRSGroupBasedLoadBalancerWithStochasticLoadBalancerAsInternal 057 extends RSGroupableBalancerTestBase { 058 @ClassRule 059 public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass( 060 TestRSGroupBasedLoadBalancerWithStochasticLoadBalancerAsInternal.class); 061 private static RSGroupBasedLoadBalancer loadBalancer; 062 063 @BeforeClass 064 public static void beforeAllTests() throws Exception { 065 groups = new String[] { RSGroupInfo.DEFAULT_GROUP }; 066 servers = generateServers(3); 067 groupMap = constructGroupInfo(servers, groups); 068 tableDescs = constructTableDesc(false); 069 Configuration conf = HBaseConfiguration.create(); 070 conf.set("hbase.regions.slop", "0"); 071 conf.setFloat("hbase.master.balancer.stochastic.readRequestCost", 10000f); 072 conf.set("hbase.rsgroup.grouploadbalancer.class", 073 StochasticLoadBalancer.class.getCanonicalName()); 074 loadBalancer = new RSGroupBasedLoadBalancer(); 075 loadBalancer.setRsGroupInfoManager(getMockedGroupInfoManager()); 076 loadBalancer.setMasterServices(getMockedMaster()); 077 loadBalancer.setConf(conf); 078 loadBalancer.initialize(); 079 } 080 081 private ServerMetrics mockServerMetricsWithReadRequests(ServerName server, 082 List<RegionInfo> regionsOnServer, long readRequestCount) { 083 ServerMetrics serverMetrics = mock(ServerMetrics.class); 084 Map<byte[], RegionMetrics> regionLoadMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 085 for(RegionInfo info : regionsOnServer){ 086 RegionMetrics rl = mock(RegionMetrics.class); 087 when(rl.getReadRequestCount()).thenReturn(readRequestCount); 088 when(rl.getWriteRequestCount()).thenReturn(0L); 089 when(rl.getMemStoreSize()).thenReturn(Size.ZERO); 090 when(rl.getStoreFileSize()).thenReturn(Size.ZERO); 091 regionLoadMap.put(info.getRegionName(), rl); 092 } 093 when(serverMetrics.getRegionMetrics()).thenReturn(regionLoadMap); 094 return serverMetrics; 095 } 096 097 /** 098 * Test HBASE-20791 099 */ 100 @Test 101 public void testBalanceCluster() throws IOException { 102 // mock cluster State 103 Map<ServerName, List<RegionInfo>> clusterState = new HashMap<ServerName, List<RegionInfo>>(); 104 ServerName serverA = servers.get(0); 105 ServerName serverB = servers.get(1); 106 ServerName serverC = servers.get(2); 107 List<RegionInfo> regionsOnServerA = randomRegions(3); 108 List<RegionInfo> regionsOnServerB = randomRegions(3); 109 List<RegionInfo> regionsOnServerC = randomRegions(3); 110 clusterState.put(serverA, regionsOnServerA); 111 clusterState.put(serverB, regionsOnServerB); 112 clusterState.put(serverC, regionsOnServerC); 113 // mock ClusterMetrics 114 Map<ServerName, ServerMetrics> serverMetricsMap = new TreeMap<>(); 115 serverMetricsMap.put(serverA, mockServerMetricsWithReadRequests(serverA, regionsOnServerA, 0)); 116 serverMetricsMap.put(serverB, mockServerMetricsWithReadRequests(serverB, regionsOnServerB, 0)); 117 serverMetricsMap.put(serverC, mockServerMetricsWithReadRequests(serverC, regionsOnServerC, 0)); 118 ClusterMetrics clusterStatus = mock(ClusterMetrics.class); 119 when(clusterStatus.getLiveServerMetrics()).thenReturn(serverMetricsMap); 120 loadBalancer.setClusterMetrics(clusterStatus); 121 122 // ReadRequestCostFunction are Rate based, So doing setClusterMetrics again 123 // this time, regions on serverA with more readRequestCount load 124 // serverA : 1000,1000,1000 125 // serverB : 0,0,0 126 // serverC : 0,0,0 127 // so should move two regions from serverA to serverB & serverC 128 serverMetricsMap = new TreeMap<>(); 129 serverMetricsMap.put(serverA, mockServerMetricsWithReadRequests(serverA, 130 regionsOnServerA, 1000)); 131 serverMetricsMap.put(serverB, mockServerMetricsWithReadRequests(serverB, regionsOnServerB, 0)); 132 serverMetricsMap.put(serverC, mockServerMetricsWithReadRequests(serverC, regionsOnServerC, 0)); 133 clusterStatus = mock(ClusterMetrics.class); 134 when(clusterStatus.getLiveServerMetrics()).thenReturn(serverMetricsMap); 135 loadBalancer.setClusterMetrics(clusterStatus); 136 137 Map<TableName, Map<ServerName, List<RegionInfo>>> LoadOfAllTable = 138 (Map) mockClusterServersWithTables(clusterState); 139 List<RegionPlan> plans = loadBalancer.balanceCluster(LoadOfAllTable); 140 Set<RegionInfo> regionsMoveFromServerA = new HashSet<>(); 141 Set<ServerName> targetServers = new HashSet<>(); 142 for(RegionPlan plan : plans) { 143 if(plan.getSource().equals(serverA)) { 144 regionsMoveFromServerA.add(plan.getRegionInfo()); 145 targetServers.add(plan.getDestination()); 146 } 147 } 148 // should move 2 regions from serverA, one moves to serverB, the other moves to serverC 149 assertEquals(2, regionsMoveFromServerA.size()); 150 assertEquals(2, targetServers.size()); 151 assertTrue(regionsOnServerA.containsAll(regionsMoveFromServerA)); 152 } 153}