View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.master.balancer;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  import static org.mockito.Mockito.mock;
23  import static org.mockito.Mockito.when;
24  
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.TreeMap;
31  
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.ClusterStatus;
34  import org.apache.hadoop.hbase.HBaseConfiguration;
35  import org.apache.hadoop.hbase.HBaseIOException;
36  import org.apache.hadoop.hbase.HRegionInfo;
37  import org.apache.hadoop.hbase.RegionLoad;
38  import org.apache.hadoop.hbase.ServerLoad;
39  import org.apache.hadoop.hbase.ServerName;
40  import org.apache.hadoop.hbase.master.RegionPlan;
41  import org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer;
42  import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
43  import org.apache.hadoop.hbase.testclassification.SmallTests;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.junit.BeforeClass;
46  import org.junit.Test;
47  import org.junit.experimental.categories.Category;
48  import org.mockito.Mockito;
49  import org.mockito.invocation.InvocationOnMock;
50  import org.mockito.stubbing.Answer;
51  
52  /**
53   * Test RSGroupBasedLoadBalancer with StochasticLoadBalancer as internal balancer
54   */
55  @Category(SmallTests.class)
56  public class TestRSGroupBasedLoadBalancerWithStochasticLoadBalancerAsInternal
57      extends RSGroupableBalancerTestBase {
58    private static RSGroupBasedLoadBalancer loadBalancer;
59  
60    @BeforeClass
61    public static void beforeAllTests() throws Exception {
62      groups = new String[] { RSGroupInfo.DEFAULT_GROUP };
63      servers = generateServers(3);
64      groupMap = constructGroupInfo(servers, groups);
65      tableDescs = constructTableDesc(false);
66      Configuration conf = HBaseConfiguration.create();
67      conf.set("hbase.regions.slop", "0");
68      conf.setFloat("hbase.master.balancer.stochastic.readRequestCost", 10000f);
69      conf.set("hbase.rsgroup.grouploadbalancer.class",
70          StochasticLoadBalancer.class.getCanonicalName());
71      loadBalancer = new RSGroupBasedLoadBalancer(getMockedGroupInfoManager());
72      loadBalancer.setMasterServices(getMockedMaster());
73      loadBalancer.setConf(conf);
74      loadBalancer.initialize();
75    }
76  
77    private ServerLoad mockServerLoadWithReadRequests(ServerName server,
78        List<HRegionInfo> regionsOnServer, long readRequestCount) {
79      ServerLoad serverMetrics = mock(ServerLoad.class);
80      Map<byte[], RegionLoad> regionLoadMap = new TreeMap<>(Bytes.BYTES_COMPARATOR);
81      for(HRegionInfo info : regionsOnServer){
82        RegionLoad rl = mock(RegionLoad.class);
83        when(rl.getReadRequestsCount()).thenReturn(readRequestCount);
84        when(rl.getWriteRequestsCount()).thenReturn(0L);
85        when(rl.getMemStoreSizeMB()).thenReturn(0);
86        when(rl.getStorefileSizeMB()).thenReturn(0);
87        regionLoadMap.put(info.getRegionName(), rl);
88      }
89      when(serverMetrics.getRegionsLoad()).thenReturn(regionLoadMap);
90      return serverMetrics;
91    }
92  
93    /**
94     * Test HBASE-20791
95     */
96    @Test
97    public void testBalanceCluster() throws HBaseIOException {
98      // mock cluster State
99      Map<ServerName, List<HRegionInfo>> clusterState = new HashMap<ServerName, List<HRegionInfo>>();
100     ServerName serverA = servers.get(0);
101     ServerName serverB = servers.get(1);
102     ServerName serverC = servers.get(2);
103     List<HRegionInfo> regionsOnServerA = randomRegions(3);
104     List<HRegionInfo> regionsOnServerB = randomRegions(3);
105     List<HRegionInfo> regionsOnServerC = randomRegions(3);
106     clusterState.put(serverA, regionsOnServerA);
107     clusterState.put(serverB, regionsOnServerB);
108     clusterState.put(serverC, regionsOnServerC);
109     // mock ClusterMetrics
110     final Map<ServerName, ServerLoad> serverMetricsMap = new TreeMap<>();
111     serverMetricsMap.put(serverA, mockServerLoadWithReadRequests(serverA, regionsOnServerA, 0));
112     serverMetricsMap.put(serverB, mockServerLoadWithReadRequests(serverB, regionsOnServerB, 0));
113     serverMetricsMap.put(serverC, mockServerLoadWithReadRequests(serverC, regionsOnServerC, 0));
114     ClusterStatus clusterStatus = mock(ClusterStatus.class);
115     when(clusterStatus.getServers()).thenReturn(serverMetricsMap.keySet());
116     when(clusterStatus.getLoad(Mockito.any(ServerName.class)))
117         .thenAnswer(new Answer<ServerLoad>() {
118           @Override
119           public ServerLoad answer(InvocationOnMock invocation) throws Throwable {
120             return serverMetricsMap.get(invocation.getArguments()[0]);
121           }
122         });
123     loadBalancer.setClusterStatus(clusterStatus);
124 
125     // ReadRequestCostFunction are Rate based, So doing setClusterMetrics again
126     // this time, regions on serverA with more readRequestCount load
127     // serverA : 1000,1000,1000
128     // serverB : 0,0,0
129     // serverC : 0,0,0
130     // so should move two regions from serverA to serverB & serverC
131     final Map<ServerName, ServerLoad> serverMetricsMap2 = new TreeMap<>();
132     serverMetricsMap2.put(serverA, mockServerLoadWithReadRequests(serverA,
133         regionsOnServerA, 1000));
134     serverMetricsMap2.put(serverB, mockServerLoadWithReadRequests(serverB, regionsOnServerB, 0));
135     serverMetricsMap2.put(serverC, mockServerLoadWithReadRequests(serverC, regionsOnServerC, 0));
136     clusterStatus = mock(ClusterStatus.class);
137     when(clusterStatus.getServers()).thenReturn(serverMetricsMap2.keySet());
138     when(clusterStatus.getLoad(Mockito.any(ServerName.class)))
139         .thenAnswer(new Answer<ServerLoad>() {
140           @Override
141           public ServerLoad answer(InvocationOnMock invocation) throws Throwable {
142             return serverMetricsMap2.get(invocation.getArguments()[0]);
143           }
144         });
145     loadBalancer.setClusterStatus(clusterStatus);
146 
147     List<RegionPlan> plans = loadBalancer.balanceCluster(clusterState);
148     Set<HRegionInfo> regionsMoveFromServerA = new HashSet<>();
149     Set<ServerName> targetServers = new HashSet<>();
150     for(RegionPlan plan : plans) {
151       if(plan.getSource().equals(serverA)) {
152         regionsMoveFromServerA.add(plan.getRegionInfo());
153         targetServers.add(plan.getDestination());
154       }
155     }
156     // should move 2 regions from serverA, one moves to serverB, the other moves to serverC
157     assertEquals(2, regionsMoveFromServerA.size());
158     assertEquals(2, targetServers.size());
159     assertTrue(regionsOnServerA.containsAll(regionsMoveFromServerA));
160   }
161 }