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.hbase.ClusterMetrics; 033import org.apache.hadoop.hbase.HBaseClassTestRule; 034import org.apache.hadoop.hbase.RegionMetrics; 035import org.apache.hadoop.hbase.ServerMetrics; 036import org.apache.hadoop.hbase.ServerName; 037import org.apache.hadoop.hbase.Size; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.client.RegionInfo; 040import org.apache.hadoop.hbase.master.RegionPlan; 041import org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer; 042import org.apache.hadoop.hbase.rsgroup.RSGroupInfo; 043import org.apache.hadoop.hbase.testclassification.LargeTests; 044import org.apache.hadoop.hbase.util.Bytes; 045import org.apache.hadoop.net.DNSToSwitchMapping; 046import org.junit.BeforeClass; 047import org.junit.ClassRule; 048import org.junit.Test; 049import org.junit.experimental.categories.Category; 050 051/** 052 * Test RSGroupBasedLoadBalancer with StochasticLoadBalancer as internal balancer 053 */ 054@Category(LargeTests.class) 055public class TestRSGroupBasedLoadBalancerWithStochasticLoadBalancerAsInternal 056 extends RSGroupableBalancerTestBase { 057 @ClassRule 058 public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule 059 .forClass(TestRSGroupBasedLoadBalancerWithStochasticLoadBalancerAsInternal.class); 060 private static RSGroupBasedLoadBalancer loadBalancer; 061 062 @BeforeClass 063 public static void beforeAllTests() throws Exception { 064 groups = new String[] { RSGroupInfo.DEFAULT_GROUP }; 065 servers = generateServers(3); 066 groupMap = constructGroupInfo(servers, groups); 067 tableDescs = constructTableDesc(false); 068 conf.set("hbase.regions.slop", "0"); 069 conf.setFloat("hbase.master.balancer.stochastic.readRequestCost", 10000f); 070 conf.set("hbase.rsgroup.grouploadbalancer.class", 071 StochasticLoadBalancer.class.getCanonicalName()); 072 conf.setClass("hbase.util.ip.to.rack.determiner", MockMapping.class, DNSToSwitchMapping.class); 073 loadBalancer = new RSGroupBasedLoadBalancer(); 074 loadBalancer.setRsGroupInfoManager(getMockedGroupInfoManager()); 075 loadBalancer.setMasterServices(getMockedMaster()); 076 loadBalancer.initialize(); 077 } 078 079 private ServerMetrics mockServerMetricsWithReadRequests(ServerName server, 080 List<RegionInfo> regionsOnServer, long readRequestCount) { 081 ServerMetrics serverMetrics = mock(ServerMetrics.class); 082 Map<byte[], RegionMetrics> regionLoadMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 083 for (RegionInfo info : regionsOnServer) { 084 RegionMetrics rl = mock(RegionMetrics.class); 085 when(rl.getReadRequestCount()).thenReturn(readRequestCount); 086 when(rl.getWriteRequestCount()).thenReturn(0L); 087 when(rl.getMemStoreSize()).thenReturn(Size.ZERO); 088 when(rl.getStoreFileSize()).thenReturn(Size.ZERO); 089 when(rl.getRegionSizeMB()).thenReturn(Size.ZERO); 090 when(rl.getCurrentRegionCachedRatio()).thenReturn(0.0f); 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.updateClusterMetrics(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, 130 mockServerMetricsWithReadRequests(serverA, 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.updateClusterMetrics(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}