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.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.io.IOException; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.Comparator; 029import java.util.List; 030import java.util.Set; 031import org.apache.hadoop.conf.Configuration; 032import org.apache.hadoop.hbase.HBaseClassTestRule; 033import org.apache.hadoop.hbase.HBaseTestingUtility; 034import org.apache.hadoop.hbase.HConstants; 035import org.apache.hadoop.hbase.HRegionLocation; 036import org.apache.hadoop.hbase.ServerName; 037import org.apache.hadoop.hbase.StartMiniClusterOption; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.Waiter; 040import org.apache.hadoop.hbase.master.HMaster; 041import org.apache.hadoop.hbase.testclassification.ClientTests; 042import org.apache.hadoop.hbase.testclassification.MediumTests; 043import org.junit.AfterClass; 044import org.junit.BeforeClass; 045import org.junit.ClassRule; 046import org.junit.Test; 047import org.junit.experimental.categories.Category; 048 049import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 050 051@Category({ MediumTests.class, ClientTests.class }) 052public class TestMasterRegistry { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestMasterRegistry.class); 057 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 058 059 @BeforeClass 060 public static void setUp() throws Exception { 061 StartMiniClusterOption.Builder builder = StartMiniClusterOption.builder(); 062 builder.numMasters(3).numRegionServers(3); 063 TEST_UTIL.startMiniCluster(builder.build()); 064 HBaseTestingUtility.setReplicas(TEST_UTIL.getAdmin(), TableName.META_TABLE_NAME, 3); 065 } 066 067 @AfterClass 068 public static void tearDown() throws Exception { 069 TEST_UTIL.shutdownMiniCluster(); 070 } 071 072 /** 073 * Generates a string of dummy master addresses in host:port format. Every other hostname won't 074 * have a port number. 075 */ 076 private static String generateDummyMastersList(int size) { 077 List<String> masters = new ArrayList<>(); 078 for (int i = 0; i < size; i++) { 079 masters.add(" localhost" + (i % 2 == 0 ? ":" + (1000 + i) : "")); 080 } 081 return String.join(",", masters); 082 } 083 084 /** 085 * Makes sure the master registry parses the master end points in the configuration correctly. 086 */ 087 @Test 088 public void testMasterAddressParsing() throws IOException { 089 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 090 int numMasters = 10; 091 conf.set(HConstants.MASTER_ADDRS_KEY, generateDummyMastersList(numMasters)); 092 try (MasterRegistry registry = new MasterRegistry(conf)) { 093 List<ServerName> parsedMasters = new ArrayList<>(registry.getParsedServers()); 094 // Half of them would be without a port, duplicates are removed. 095 assertEquals(numMasters / 2 + 1, parsedMasters.size()); 096 // Sort in the increasing order of port numbers. 097 Collections.sort(parsedMasters, Comparator.comparingInt(ServerName::getPort)); 098 for (int i = 0; i < parsedMasters.size(); i++) { 099 ServerName sn = parsedMasters.get(i); 100 assertEquals("localhost", sn.getHostname()); 101 if (i == parsedMasters.size() - 1) { 102 // Last entry should be the one with default port. 103 assertEquals(HConstants.DEFAULT_MASTER_PORT, sn.getPort()); 104 } else { 105 assertEquals(1000 + (2 * i), sn.getPort()); 106 } 107 } 108 } 109 } 110 111 @Test 112 public void testRegistryRPCs() throws Exception { 113 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 114 HMaster activeMaster = TEST_UTIL.getHBaseCluster().getMaster(); 115 final int size = 116 activeMaster.getMetaRegionLocationCache().getMetaRegionLocations().get().size(); 117 for (int numHedgedReqs = 1; numHedgedReqs <= size; numHedgedReqs++) { 118 conf.setInt(MasterRegistry.MASTER_REGISTRY_HEDGED_REQS_FANOUT_KEY, numHedgedReqs); 119 try (MasterRegistry registry = new MasterRegistry(conf)) { 120 // Add wait on all replicas being assigned before proceeding w/ test. Failed on occasion 121 // because not all replicas had made it up before test started. 122 RegionReplicaTestHelper.waitUntilAllMetaReplicasAreReady(TEST_UTIL, registry); 123 assertEquals(registry.getClusterId().get(), activeMaster.getClusterId()); 124 assertEquals(registry.getActiveMaster().get(), activeMaster.getServerName()); 125 List<HRegionLocation> metaLocations = 126 Arrays.asList(registry.getMetaRegionLocations().get().getRegionLocations()); 127 List<HRegionLocation> actualMetaLocations = 128 activeMaster.getMetaRegionLocationCache().getMetaRegionLocations().get(); 129 Collections.sort(metaLocations); 130 Collections.sort(actualMetaLocations); 131 assertEquals(actualMetaLocations, metaLocations); 132 } 133 } 134 } 135 136 /** 137 * Tests that the list of masters configured in the MasterRegistry is dynamically refreshed in the 138 * event of errors. 139 */ 140 @Test 141 public void testDynamicMasterConfigurationRefresh() throws Exception { 142 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 143 String currentMasterAddrs = Preconditions.checkNotNull(conf.get(HConstants.MASTER_ADDRS_KEY)); 144 HMaster activeMaster = TEST_UTIL.getHBaseCluster().getMaster(); 145 String clusterId = activeMaster.getClusterId(); 146 // Add a non-working master 147 ServerName badServer = ServerName.valueOf("localhost", 1234, -1); 148 conf.set(HConstants.MASTER_ADDRS_KEY, badServer.toShortString() + "," + currentMasterAddrs); 149 // Set the hedging fan out so that all masters are queried. 150 conf.setInt(MasterRegistry.MASTER_REGISTRY_HEDGED_REQS_FANOUT_KEY, 4); 151 // Do not limit the number of refreshes during the test run. 152 conf.setLong(MasterRegistry.MASTER_REGISTRY_MIN_SECS_BETWEEN_REFRESHES, 0); 153 try (MasterRegistry registry = new MasterRegistry(conf)) { 154 final Set<ServerName> masters = registry.getParsedServers(); 155 assertTrue(masters.contains(badServer)); 156 // Make a registry RPC, this should trigger a refresh since one of the hedged RPC fails. 157 assertEquals(registry.getClusterId().get(), clusterId); 158 // Wait for new set of masters to be populated. 159 TEST_UTIL.waitFor(5000, 160 (Waiter.Predicate<Exception>) () -> !registry.getParsedServers().equals(masters)); 161 // new set of masters should not include the bad server 162 final Set<ServerName> newMasters = registry.getParsedServers(); 163 // Bad one should be out. 164 assertEquals(3, newMasters.size()); 165 assertFalse(newMasters.contains(badServer)); 166 // Kill the active master 167 activeMaster.stopMaster(); 168 TEST_UTIL.waitFor(10000, 169 () -> TEST_UTIL.getMiniHBaseCluster().getLiveMasterThreads().size() == 2); 170 TEST_UTIL.getMiniHBaseCluster().waitForActiveAndReadyMaster(10000); 171 // Wait until the killed master de-registered. This should also trigger another refresh. 172 TEST_UTIL.waitFor(10000, () -> registry.getMasters().get().size() == 2); 173 TEST_UTIL.waitFor(20000, () -> registry.getParsedServers().size() == 2); 174 final Set<ServerName> newMasters2 = registry.getParsedServers(); 175 assertEquals(2, newMasters2.size()); 176 assertFalse(newMasters2.contains(activeMaster.getServerName())); 177 } finally { 178 // Reset the state, add a killed master. 179 TEST_UTIL.getMiniHBaseCluster().startMaster(); 180 } 181 } 182}