| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.hadoop.hbase.master; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| |
| import org.apache.commons.cli.CommandLine; |
| import org.apache.commons.cli.GnuParser; |
| import org.apache.commons.cli.Options; |
| import org.apache.commons.cli.ParseException; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.hbase.CoordinatedStateManager; |
| import org.apache.hadoop.hbase.CoordinatedStateManagerFactory; |
| import org.apache.hadoop.hbase.HConstants; |
| import org.apache.hadoop.hbase.LocalHBaseCluster; |
| import org.apache.hadoop.hbase.MasterNotRunningException; |
| import org.apache.hadoop.hbase.ZNodeClearer; |
| import org.apache.hadoop.hbase.ZooKeeperConnectionException; |
| import org.apache.hadoop.hbase.classification.InterfaceAudience; |
| import org.apache.hadoop.hbase.client.Admin; |
| import org.apache.hadoop.hbase.client.Connection; |
| import org.apache.hadoop.hbase.client.ConnectionFactory; |
| import org.apache.hadoop.hbase.regionserver.HRegionServer; |
| import org.apache.hadoop.hbase.util.JVMClusterUtil; |
| import org.apache.hadoop.hbase.util.ServerCommandLine; |
| import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster; |
| import org.apache.hadoop.hbase.zookeeper.ZKUtil; |
| import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; |
| import org.apache.zookeeper.KeeperException; |
| |
| @InterfaceAudience.Private |
| public class HMasterCommandLine extends ServerCommandLine { |
| private static final Log LOG = LogFactory.getLog(HMasterCommandLine.class); |
| |
| private static final String USAGE = |
| "Usage: Master [opts] start|stop|clear\n" + |
| " start Start Master. If local mode, start Master and RegionServer in same JVM\n" + |
| " stop Start cluster shutdown; Master signals RegionServer shutdown\n" + |
| " clear Delete the master znode in ZooKeeper after a master crashes\n "+ |
| " where [opts] are:\n" + |
| " --minRegionServers=<servers> Minimum RegionServers needed to host user tables.\n" + |
| " --localRegionServers=<servers> " + |
| "RegionServers to start in master process when in standalone mode.\n" + |
| " --masters=<servers> Masters to start in this process.\n" + |
| " --backup Master should start in backup mode"; |
| |
| private final Class<? extends HMaster> masterClass; |
| |
| public HMasterCommandLine(Class<? extends HMaster> masterClass) { |
| this.masterClass = masterClass; |
| } |
| |
| protected String getUsage() { |
| return USAGE; |
| } |
| |
| |
| public int run(String args[]) throws Exception { |
| Options opt = new Options(); |
| opt.addOption("localRegionServers", true, |
| "RegionServers to start in master process when running standalone"); |
| opt.addOption("masters", true, "Masters to start in this process"); |
| opt.addOption("minRegionServers", true, "Minimum RegionServers needed to host user tables"); |
| opt.addOption("backup", false, "Do not try to become HMaster until the primary fails"); |
| |
| CommandLine cmd; |
| try { |
| cmd = new GnuParser().parse(opt, args); |
| } catch (ParseException e) { |
| LOG.error("Could not parse: ", e); |
| usage(null); |
| return 1; |
| } |
| |
| |
| if (cmd.hasOption("minRegionServers")) { |
| String val = cmd.getOptionValue("minRegionServers"); |
| getConf().setInt("hbase.regions.server.count.min", |
| Integer.parseInt(val)); |
| LOG.debug("minRegionServers set to " + val); |
| } |
| |
| // minRegionServers used to be minServers. Support it too. |
| if (cmd.hasOption("minServers")) { |
| String val = cmd.getOptionValue("minServers"); |
| getConf().setInt("hbase.regions.server.count.min", Integer.parseInt(val)); |
| LOG.debug("minServers set to " + val); |
| } |
| |
| // check if we are the backup master - override the conf if so |
| if (cmd.hasOption("backup")) { |
| getConf().setBoolean(HConstants.MASTER_TYPE_BACKUP, true); |
| } |
| |
| // How many regionservers to startup in this process (we run regionservers in same process as |
| // master when we are in local/standalone mode. Useful testing) |
| if (cmd.hasOption("localRegionServers")) { |
| String val = cmd.getOptionValue("localRegionServers"); |
| getConf().setInt("hbase.regionservers", Integer.parseInt(val)); |
| LOG.debug("localRegionServers set to " + val); |
| } |
| // How many masters to startup inside this process; useful testing |
| if (cmd.hasOption("masters")) { |
| String val = cmd.getOptionValue("masters"); |
| getConf().setInt("hbase.masters", Integer.parseInt(val)); |
| LOG.debug("masters set to " + val); |
| } |
| |
| @SuppressWarnings("unchecked") |
| List<String> remainingArgs = cmd.getArgList(); |
| if (remainingArgs.size() != 1) { |
| usage(null); |
| return 1; |
| } |
| |
| String command = remainingArgs.get(0); |
| |
| if ("start".equals(command)) { |
| return startMaster(); |
| } else if ("stop".equals(command)) { |
| return stopMaster(); |
| } else if ("clear".equals(command)) { |
| return (ZNodeClearer.clear(getConf()) ? 0 : 1); |
| } else { |
| usage("Invalid command: " + command); |
| return 1; |
| } |
| } |
| |
| private int startMaster() { |
| Configuration conf = getConf(); |
| try { |
| // If 'local', defer to LocalHBaseCluster instance. Starts master |
| // and regionserver both in the one JVM. |
| if (LocalHBaseCluster.isLocal(conf)) { |
| DefaultMetricsSystem.setMiniClusterMode(true); |
| final MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster(conf); |
| File zkDataPath = new File(conf.get(HConstants.ZOOKEEPER_DATA_DIR)); |
| |
| // find out the default client port |
| int zkClientPort = 0; |
| |
| // If the zookeeper client port is specified in server quorum, use it. |
| String zkserver = conf.get(HConstants.ZOOKEEPER_QUORUM); |
| if (zkserver != null) { |
| String[] zkservers = zkserver.split(","); |
| |
| if (zkservers.length > 1) { |
| // In local mode deployment, we have the master + a region server and zookeeper server |
| // started in the same process. Therefore, we only support one zookeeper server. |
| String errorMsg = "Could not start ZK with " + zkservers.length + |
| " ZK servers in local mode deployment. Aborting as clients (e.g. shell) will not " |
| + "be able to find this ZK quorum."; |
| System.err.println(errorMsg); |
| throw new IOException(errorMsg); |
| } |
| |
| String[] parts = zkservers[0].split(":"); |
| |
| if (parts.length == 2) { |
| // the second part is the client port |
| zkClientPort = Integer.parseInt(parts [1]); |
| } |
| } |
| // If the client port could not be find in server quorum conf, try another conf |
| if (zkClientPort == 0) { |
| zkClientPort = conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 0); |
| // The client port has to be set by now; if not, throw exception. |
| if (zkClientPort == 0) { |
| throw new IOException("No config value for " + HConstants.ZOOKEEPER_CLIENT_PORT); |
| } |
| } |
| zooKeeperCluster.setDefaultClientPort(zkClientPort); |
| // set the ZK tick time if specified |
| int zkTickTime = conf.getInt(HConstants.ZOOKEEPER_TICK_TIME, 0); |
| if (zkTickTime > 0) { |
| zooKeeperCluster.setTickTime(zkTickTime); |
| } |
| |
| // login the zookeeper server principal (if using security) |
| ZKUtil.loginServer(conf, HConstants.ZK_SERVER_KEYTAB_FILE, |
| HConstants.ZK_SERVER_KERBEROS_PRINCIPAL, null); |
| int localZKClusterSessionTimeout = |
| conf.getInt(HConstants.ZK_SESSION_TIMEOUT + ".localHBaseCluster", 10*1000); |
| conf.setInt(HConstants.ZK_SESSION_TIMEOUT, localZKClusterSessionTimeout); |
| LOG.info("Starting a zookeeper cluster"); |
| int clientPort = zooKeeperCluster.startup(zkDataPath); |
| if (clientPort != zkClientPort) { |
| String errorMsg = "Could not start ZK at requested port of " + |
| zkClientPort + ". ZK was started at port: " + clientPort + |
| ". Aborting as clients (e.g. shell) will not be able to find " + |
| "this ZK quorum."; |
| System.err.println(errorMsg); |
| throw new IOException(errorMsg); |
| } |
| conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, Integer.toString(clientPort)); |
| |
| // Need to have the zk cluster shutdown when master is shutdown. |
| // Run a subclass that does the zk cluster shutdown on its way out. |
| int mastersCount = conf.getInt("hbase.masters", 1); |
| int regionServersCount = conf.getInt("hbase.regionservers", 1); |
| // Set start timeout to 5 minutes for cmd line start operations |
| conf.setIfUnset("hbase.master.start.timeout.localHBaseCluster", "300000"); |
| LOG.info("Starting up instance of localHBaseCluster; master=" + mastersCount + |
| ", regionserversCount=" + regionServersCount); |
| LocalHBaseCluster cluster = new LocalHBaseCluster(conf, mastersCount, regionServersCount, |
| LocalHMaster.class, HRegionServer.class); |
| ((LocalHMaster)cluster.getMaster(0)).setZKCluster(zooKeeperCluster); |
| cluster.startup(); |
| waitOnMasterThreads(cluster); |
| } else { |
| logProcessInfo(getConf()); |
| CoordinatedStateManager csm = |
| CoordinatedStateManagerFactory.getCoordinatedStateManager(conf); |
| HMaster master = HMaster.constructMaster(masterClass, conf, csm); |
| if (master.isStopped()) { |
| LOG.info("Won't bring the Master up as a shutdown is requested"); |
| return 1; |
| } |
| master.start(); |
| master.join(); |
| if(master.isAborted()) |
| throw new RuntimeException("HMaster Aborted"); |
| } |
| } catch (Throwable t) { |
| LOG.error("Master exiting", t); |
| return 1; |
| } |
| return 0; |
| } |
| |
| @SuppressWarnings("resource") |
| private int stopMaster() { |
| Configuration conf = getConf(); |
| // Don't try more than once |
| conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 0); |
| try (Connection connection = ConnectionFactory.createConnection(conf)) { |
| try (Admin admin = connection.getAdmin()) { |
| admin.shutdown(); |
| } catch (Throwable t) { |
| LOG.error("Failed to stop master", t); |
| return 1; |
| } |
| } catch (MasterNotRunningException e) { |
| LOG.error("Master not running"); |
| return 1; |
| } catch (ZooKeeperConnectionException e) { |
| LOG.error("ZooKeeper not available"); |
| return 1; |
| } catch (IOException e) { |
| LOG.error("Got IOException: " +e.getMessage(), e); |
| return 1; |
| } |
| return 0; |
| } |
| |
| private void waitOnMasterThreads(LocalHBaseCluster cluster) throws InterruptedException{ |
| List<JVMClusterUtil.MasterThread> masters = cluster.getMasters(); |
| List<JVMClusterUtil.RegionServerThread> regionservers = cluster.getRegionServers(); |
| |
| if (masters != null) { |
| for (JVMClusterUtil.MasterThread t : masters) { |
| t.join(); |
| if(t.getMaster().isAborted()) { |
| closeAllRegionServerThreads(regionservers); |
| throw new RuntimeException("HMaster Aborted"); |
| } |
| } |
| } |
| } |
| |
| private static void closeAllRegionServerThreads( |
| List<JVMClusterUtil.RegionServerThread> regionservers) { |
| for(JVMClusterUtil.RegionServerThread t : regionservers){ |
| t.getRegionServer().stop("HMaster Aborted; Bringing down regions servers"); |
| } |
| } |
| |
| /* |
| * Version of master that will shutdown the passed zk cluster on its way out. |
| */ |
| public static class LocalHMaster extends HMaster { |
| private MiniZooKeeperCluster zkcluster = null; |
| |
| public LocalHMaster(Configuration conf, CoordinatedStateManager csm) |
| throws IOException, KeeperException, InterruptedException { |
| super(conf, csm); |
| } |
| |
| @Override |
| public void run() { |
| super.run(); |
| if (this.zkcluster != null) { |
| try { |
| this.zkcluster.shutdown(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| void setZKCluster(final MiniZooKeeperCluster zkcluster) { |
| this.zkcluster = zkcluster; |
| } |
| } |
| } |