View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master.balancer;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  
26  import com.google.common.collect.ArrayListMultimap;
27  
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  
37  import org.apache.commons.lang.StringUtils;
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.apache.hadoop.conf.Configuration;
41  import org.apache.hadoop.hbase.HBaseConfiguration;
42  import org.apache.hadoop.hbase.HRegionInfo;
43  import org.apache.hadoop.hbase.ServerName;
44  import org.apache.hadoop.hbase.TableName;
45  import org.apache.hadoop.hbase.master.LoadBalancer;
46  import org.apache.hadoop.hbase.master.RegionPlan;
47  import org.apache.hadoop.hbase.net.Address;
48  import org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer;
49  import org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
50  import org.apache.hadoop.hbase.testclassification.SmallTests;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  import org.junit.experimental.categories.Category;
54  
55  /**
56   * Test RSGroupBasedLoadBalancer with SimpleLoadBalancer as internal balancer
57   */
58  @Category(SmallTests.class)
59  public class TestRSGroupBasedLoadBalancer extends RSGroupableBalancerTestBase {
60    private static final Log LOG = LogFactory.getLog(TestRSGroupBasedLoadBalancer.class);
61    private static RSGroupBasedLoadBalancer loadBalancer;
62  
63    @BeforeClass
64    public static void beforeAllTests() throws Exception {
65      servers = generateServers(7);
66      groupMap = constructGroupInfo(servers, groups);
67      tableDescs = constructTableDesc(true);
68      Configuration conf = HBaseConfiguration.create();
69      conf.set("hbase.regions.slop", "0");
70      conf.set("hbase.group.grouploadbalancer.class", SimpleLoadBalancer.class.getCanonicalName());
71      loadBalancer = new RSGroupBasedLoadBalancer(getMockedGroupInfoManager());
72      loadBalancer.setMasterServices(getMockedMaster());
73      loadBalancer.setConf(conf);
74      loadBalancer.initialize();
75    }
76  
77    /**
78     * Test the load balancing algorithm.
79     * Invariant is that all servers of the group should be hosting either floor(average) or
80     * ceiling(average)
81     */
82    @Test
83    public void testBalanceCluster() throws Exception {
84      Map<ServerName, List<HRegionInfo>> servers = mockClusterServers();
85      ArrayListMultimap<String, ServerAndLoad> list = convertToGroupBasedMap(servers);
86      LOG.info("Mock Cluster :  " + printStats(list));
87      List<RegionPlan> plans = loadBalancer.balanceCluster(servers);
88      ArrayListMultimap<String, ServerAndLoad> balancedCluster = reconcile(
89          list, plans);
90      LOG.info("Mock Balance : " + printStats(balancedCluster));
91      assertClusterAsBalanced(balancedCluster);
92    }
93  
94    /**
95     * Tests the bulk assignment used during cluster startup.
96     * Round-robin. Should yield a balanced cluster so same invariant as the
97     * load balancer holds, all servers holding either floor(avg) or
98     * ceiling(avg).
99     */
100   @Test
101   public void testBulkAssignment() throws Exception {
102     List<HRegionInfo> regions = randomRegions(25);
103     Map<ServerName, List<HRegionInfo>> assignments = loadBalancer
104         .roundRobinAssignment(regions, servers);
105     //test empty region/servers scenario
106     //this should not throw an NPE
107     loadBalancer.roundRobinAssignment(regions, Collections.<ServerName>emptyList());
108     //test regular scenario
109     assertTrue(assignments.keySet().size() == servers.size());
110     for (ServerName sn : assignments.keySet()) {
111       List<HRegionInfo> regionAssigned = assignments.get(sn);
112       for (HRegionInfo region : regionAssigned) {
113         TableName tableName = region.getTable();
114         String groupName =
115             getMockedGroupInfoManager().getRSGroupOfTable(tableName);
116         assertTrue(StringUtils.isNotEmpty(groupName));
117         RSGroupInfo gInfo = getMockedGroupInfoManager().getRSGroup(
118             groupName);
119         assertTrue(
120             "Region is not correctly assigned to group servers.",
121             gInfo.containsServer(sn.getAddress()));
122       }
123     }
124     ArrayListMultimap<String, ServerAndLoad> loadMap = convertToGroupBasedMap(assignments);
125     assertClusterAsBalanced(loadMap);
126   }
127 
128   /**
129    * Test the cluster startup bulk assignment which attempts to retain
130    * assignment info.
131    */
132   @Test
133   public void testRetainAssignment() throws Exception {
134     // Test simple case where all same servers are there
135     Map<ServerName, List<HRegionInfo>> currentAssignments = mockClusterServers();
136     Map<HRegionInfo, ServerName> inputForTest = new HashMap<HRegionInfo, ServerName>();
137     for (ServerName sn : currentAssignments.keySet()) {
138       for (HRegionInfo region : currentAssignments.get(sn)) {
139         inputForTest.put(region, sn);
140       }
141     }
142     //verify region->null server assignment is handled
143     inputForTest.put(randomRegions(1).get(0), null);
144     Map<ServerName, List<HRegionInfo>> newAssignment = loadBalancer
145         .retainAssignment(inputForTest, servers);
146     assertRetainedAssignment(inputForTest, servers, newAssignment);
147   }
148 
149   @Test
150   public void testGetMisplacedRegions() throws Exception {
151     // Test case where region is not considered misplaced if RSGroupInfo cannot be determined
152     Map<HRegionInfo, ServerName> inputForTest = new HashMap<>();
153     HRegionInfo ri = new HRegionInfo(
154         table0, new byte[16], new byte[16], false, regionId++);
155     inputForTest.put(ri, servers.iterator().next());
156     Set<HRegionInfo> misplacedRegions = loadBalancer.getMisplacedRegions(inputForTest);
157     assertFalse(misplacedRegions.contains(ri));
158   }
159 
160   /**
161    * Test BOGUS_SERVER_NAME among groups do not overwrite each other
162    */
163   @Test
164   public void testRoundRobinAssignment() throws Exception {
165     List<ServerName> onlineServers = new ArrayList<ServerName>(servers.size());
166     onlineServers.addAll(servers);
167     List<HRegionInfo> regions = randomRegions(25);
168     int bogusRegion = 0;
169     for(HRegionInfo region : regions){
170       String group = tableMap.get(region.getTable());
171       if("dg3".equals(group) || "dg4".equals(group)){
172         bogusRegion++;
173       }
174     }
175     Set<Address> offlineServers = new HashSet<Address>();
176     offlineServers.addAll(groupMap.get("dg3").getServers());
177     offlineServers.addAll(groupMap.get("dg4").getServers());
178     for(Iterator<ServerName> it =  onlineServers.iterator(); it.hasNext();){
179       ServerName server = it.next();
180       Address address = server.getAddress();
181       if(offlineServers.contains(address)){
182         it.remove();
183       }
184     }
185     Map<ServerName, List<HRegionInfo>> assignments = loadBalancer
186         .roundRobinAssignment(regions, onlineServers);
187     assertEquals(bogusRegion, assignments.get(LoadBalancer.BOGUS_SERVER_NAME).size());
188   }
189 }