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.rsgroup;
19  
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.IOException;
23  import java.util.Collections;
24  
25  import org.apache.hadoop.hbase.HBaseTestingUtility;
26  import org.apache.hadoop.hbase.HColumnDescriptor;
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.HTableDescriptor;
30  import org.apache.hadoop.hbase.NamespaceDescriptor;
31  import org.apache.hadoop.hbase.ProcedureInfo;
32  import org.apache.hadoop.hbase.ServerName;
33  import org.apache.hadoop.hbase.TableName;
34  import org.apache.hadoop.hbase.Waiter;
35  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
36  import org.apache.hadoop.hbase.master.ServerManager;
37  import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
38  import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
39  import org.apache.hadoop.hbase.net.Address;
40  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
41  import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos;
42  import org.apache.hadoop.hbase.testclassification.MediumTests;
43  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
44  import org.apache.hadoop.hbase.util.JVMClusterUtil;
45  import org.apache.hadoop.hbase.util.Threads;
46  import org.junit.After;
47  import org.junit.AfterClass;
48  import org.junit.Before;
49  import org.junit.BeforeClass;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  import org.slf4j.Logger;
53  import org.slf4j.LoggerFactory;
54  
55  @Category({ MediumTests.class })
56  public class TestRSGroupsFallback extends TestRSGroupsBase {
57    protected static final Logger LOG = LoggerFactory.getLogger(TestRSGroupsFallback.class);
58  
59    private static final String FALLBACK_GROUP = "fallback";
60  
61    @BeforeClass
62    public static void setUp() throws Exception {
63      TEST_UTIL = new HBaseTestingUtility();
64      TEST_UTIL.getConfiguration().setBoolean(RSGroupBasedLoadBalancer.FALLBACK_GROUP_ENABLE_KEY,
65        true);
66      TEST_UTIL.getConfiguration().setFloat(
67        "hbase.master.balancer.stochastic.tableSkewCost", 6000);
68      TEST_UTIL.getConfiguration().set(
69        HConstants.HBASE_MASTER_LOADBALANCER_CLASS,
70        RSGroupBasedLoadBalancer.class.getName());
71      TEST_UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
72        RSGroupAdminEndpoint.class.getName() + "," + CPMasterObserver.class.getName());
73      TEST_UTIL.getConfiguration().setBoolean(
74        HConstants.ZOOKEEPER_USEMULTI,
75        true);
76      TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE - 1);
77      TEST_UTIL.getConfiguration().setInt(
78        ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART,
79        NUM_SLAVES_BASE - 1);
80      TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
81      initialize();
82      master.balanceSwitch(true);
83    }
84  
85    @AfterClass
86    public static void tearDown() throws Exception {
87      tearDownAfterClass();
88    }
89  
90    @Before
91    public void beforeMethod() throws Exception {
92      setUpBeforeMethod();
93    }
94  
95    @After
96    public void afterMethod() throws Exception {
97      tearDownAfterMethod();
98    }
99  
100   @Test
101   public void testFallback() throws Exception {
102     // add fallback group
103     addGroup(rsGroupAdmin, FALLBACK_GROUP, 1);
104     // add test group
105     String groupName = "appInfo";
106     RSGroupInfo appInfo = addGroup(rsGroupAdmin, groupName, 1);
107     final TableName tableName = TableName.valueOf(tablePrefix + "_ns", "_testFallback");
108     admin.createNamespace(
109       NamespaceDescriptor.create(tableName.getNamespaceAsString())
110         .addConfiguration(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP, appInfo.getName()).build());
111     final HTableDescriptor desc = new HTableDescriptor(tableName);
112     desc.addFamily(new HColumnDescriptor("f"));
113     admin.createTable(desc);
114     //wait for created table to be assigned
115     TEST_UTIL.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() {
116       @Override
117       public boolean evaluate() throws Exception {
118         return getTableRegionMap().get(desc.getTableName()) != null;
119       }
120     });
121     TEST_UTIL.waitUntilAllRegionsAssigned(tableName);
122 
123     // server of test group crash, regions move to default group
124     crashRsInGroup(groupName);
125     assertRegionsInGroup(tableName, RSGroupInfo.DEFAULT_GROUP);
126 
127     // server of default group crash, regions move to any other group
128     crashRsInGroup(RSGroupInfo.DEFAULT_GROUP);
129     assertRegionsInGroup(tableName, FALLBACK_GROUP);
130 
131     // add a new server to default group, regions move to default group
132     JVMClusterUtil.RegionServerThread t =
133       TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
134     assertTrue(master.balance());
135     assertRegionsInGroup(tableName, RSGroupInfo.DEFAULT_GROUP);
136 
137     // add a new server to test group, regions move back
138     JVMClusterUtil.RegionServerThread t1 =
139       TEST_UTIL.getMiniHBaseCluster().startRegionServerAndWait(60000);
140     rsGroupAdmin.moveServers(Collections.singleton(t.getRegionServer().getServerName()
141       .getAddress()), groupName);
142     assertTrue(master.balance());
143     assertRegionsInGroup(tableName, groupName);
144 
145     TEST_UTIL.getMiniHBaseCluster().killRegionServer(t.getRegionServer().getServerName());
146     TEST_UTIL.getMiniHBaseCluster().killRegionServer(t1.getRegionServer().getServerName());
147 
148     TEST_UTIL.deleteTable(tableName);
149   }
150 
151   private void assertRegionsInGroup(TableName table, String group) throws IOException {
152     ProcedureExecutor<MasterProcedureEnv> procExecutor = TEST_UTIL.getMiniHBaseCluster()
153       .getMaster().getMasterProcedureExecutor();
154     for (ProcedureInfo procInfo: procExecutor.listProcedures()) {
155       LOG.debug("Waiting for " + procInfo.getProcName() + " " + procInfo.toString());
156       waitProcedure(procExecutor, procInfo, 10000);
157     }
158     RSGroupInfo rsGroup = rsGroupAdmin.getRSGroupInfo(group);
159     for (HRegionInfo region: master.getAssignmentManager().getRegionStates()
160       .getRegionsOfTable(table)) {
161       Address regionOnServer = master.getAssignmentManager().getRegionStates()
162         .getRegionAssignments().get(region).getAddress();
163       assertTrue(rsGroup.getServers().contains(regionOnServer));
164     }
165   }
166 
167   private void crashRsInGroup(String groupName) throws Exception {
168     for (Address server : rsGroupAdmin.getRSGroupInfo(groupName).getServers()) {
169       final ServerName sn = getServerName(server);
170       TEST_UTIL.getMiniHBaseCluster().killRegionServer(sn);
171       TEST_UTIL.waitFor(60000, new Waiter.Predicate<Exception>() {
172         @Override
173         public boolean evaluate() {
174           return master.getServerManager().isServerDead(sn);
175         }
176       });
177     }
178     Threads.sleep(1000);
179     TEST_UTIL.waitUntilNoRegionsInTransition(60000);
180   }
181 
182   private void waitProcedure(ProcedureExecutor<MasterProcedureEnv> procExecutor,
183                              ProcedureInfo procInfo, long timeout) {
184     long start = EnvironmentEdgeManager.currentTime();
185     while ((EnvironmentEdgeManager.currentTime() - start) < timeout) {
186       if (procInfo.getProcState() == ProcedureProtos.ProcedureState.INITIALIZING ||
187         (procExecutor.isRunning() && !procExecutor.isFinished(procInfo.getProcId()))) {
188         Threads.sleep(1000);
189       } else {
190         break;
191       }
192     }
193   }
194 }