View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.commons.cli.CommandLine;
26  import org.apache.commons.cli.GnuParser;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.ParseException;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.CoordinatedStateManager;
34  import org.apache.hadoop.hbase.CoordinatedStateManagerFactory;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.LocalHBaseCluster;
37  import org.apache.hadoop.hbase.MasterNotRunningException;
38  import org.apache.hadoop.hbase.ZNodeClearer;
39  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
40  import org.apache.hadoop.hbase.client.Admin;
41  import org.apache.hadoop.hbase.client.HBaseAdmin;
42  import org.apache.hadoop.hbase.regionserver.HRegionServer;
43  import org.apache.hadoop.hbase.util.JVMClusterUtil;
44  import org.apache.hadoop.hbase.util.ServerCommandLine;
45  import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
46  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
47  import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
48  import org.apache.zookeeper.KeeperException;
49  
50  @InterfaceAudience.Private
51  public class HMasterCommandLine extends ServerCommandLine {
52    private static final Log LOG = LogFactory.getLog(HMasterCommandLine.class);
53  
54    private static final String USAGE =
55      "Usage: Master [opts] start|stop|clear\n" +
56      " start  Start Master. If local mode, start Master and RegionServer in same JVM\n" +
57      " stop   Start cluster shutdown; Master signals RegionServer shutdown\n" +
58      " clear  Delete the master znode in ZooKeeper after a master crashes\n "+
59      " where [opts] are:\n" +
60      "   --minRegionServers=<servers>   Minimum RegionServers needed to host user tables.\n" +
61      "   --localRegionServers=<servers> " +
62        "RegionServers to start in master process when in standalone mode.\n" +
63      "   --masters=<servers>            Masters to start in this process.\n" +
64      "   --backup                       Master should start in backup mode\n" +
65      "   --shutDownCluster                    " +
66      "Start Cluster shutdown; Master signals RegionServer shutdown";
67  
68    private final Class<? extends HMaster> masterClass;
69  
70    public HMasterCommandLine(Class<? extends HMaster> masterClass) {
71      this.masterClass = masterClass;
72    }
73  
74    @Override
75    protected String getUsage() {
76      return USAGE;
77    }
78  
79    @Override
80    public int run(String args[]) throws Exception {
81      boolean shutDownCluster = false;
82      Options opt = new Options();
83      opt.addOption("localRegionServers", true,
84        "RegionServers to start in master process when running standalone");
85      opt.addOption("masters", true, "Masters to start in this process");
86      opt.addOption("minRegionServers", true, "Minimum RegionServers needed to host user tables");
87      opt.addOption("backup", false, "Do not try to become HMaster until the primary fails");
88      opt.addOption("shutDownCluster", false, "`hbase master stop --shutDownCluster` shuts down cluster");
89  
90      CommandLine cmd;
91      try {
92        cmd = new GnuParser().parse(opt, args);
93      } catch (ParseException e) {
94        LOG.error("Could not parse: ", e);
95        usage(null);
96        return 1;
97      }
98  
99  
100     if (cmd.hasOption("minRegionServers")) {
101       String val = cmd.getOptionValue("minRegionServers");
102       getConf().setInt("hbase.regions.server.count.min", Integer.parseInt(val));
103       LOG.debug("minRegionServers set to " + val);
104     }
105 
106     // minRegionServers used to be minServers.  Support it too.
107     if (cmd.hasOption("minServers")) {
108       String val = cmd.getOptionValue("minServers");
109       getConf().setInt("hbase.regions.server.count.min", Integer.parseInt(val));
110       LOG.debug("minServers set to " + val);
111     }
112 
113     // check if we are the backup master - override the conf if so
114     if (cmd.hasOption("backup")) {
115       getConf().setBoolean(HConstants.MASTER_TYPE_BACKUP, true);
116     }
117 
118     // How many regionservers to startup in this process (we run regionservers in same process as
119     // master when we are in local/standalone mode. Useful testing)
120     if (cmd.hasOption("localRegionServers")) {
121       String val = cmd.getOptionValue("localRegionServers");
122       getConf().setInt("hbase.regionservers", Integer.parseInt(val));
123       LOG.debug("localRegionServers set to " + val);
124     }
125     // How many masters to startup inside this process; useful testing
126     if (cmd.hasOption("masters")) {
127       String val = cmd.getOptionValue("masters");
128       getConf().setInt("hbase.masters", Integer.parseInt(val));
129       LOG.debug("masters set to " + val);
130     }
131 
132     // Checking whether to shut down cluster or not
133     if (cmd.hasOption("shutDownCluster")) {
134       shutDownCluster = true;
135     }
136 
137     @SuppressWarnings("unchecked")
138     List<String> remainingArgs = cmd.getArgList();
139     if (remainingArgs.size() != 1) {
140       usage(null);
141       return 1;
142     }
143 
144     String command = remainingArgs.get(0);
145 
146     if ("start".equals(command)) {
147       return startMaster();
148     } else if ("stop".equals(command)) {
149       if (shutDownCluster) {
150         return stopMaster();
151       }
152       System.err.println(
153         "To shutdown the master run " +
154         "hbase-daemon.sh stop master or send a kill signal to " +
155         "the HMaster pid, " +
156         "and to stop HBase Cluster run \"stop-hbase.sh\" or \"hbase master stop --shutDownCluster\"");
157       return 1;
158     } else if ("clear".equals(command)) {
159       return (ZNodeClearer.clear(getConf()) ? 0 : 1);
160     } else {
161       usage("Invalid command: " + command);
162       return 1;
163     }
164   }
165 
166   private int startMaster() {
167     Configuration conf = getConf();
168     try {
169       // If 'local', defer to LocalHBaseCluster instance.  Starts master
170       // and regionserver both in the one JVM.
171       if (LocalHBaseCluster.isLocal(conf)) {
172         DefaultMetricsSystem.setMiniClusterMode(true);
173         final MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster(conf);
174         File zkDataPath = new File(conf.get(HConstants.ZOOKEEPER_DATA_DIR));
175 
176         // find out the default client port
177         int zkClientPort = 0;
178 
179         // If the zookeeper client port is specified in server quorum, use it.
180         String zkserver = conf.get(HConstants.ZOOKEEPER_QUORUM);
181         if (zkserver != null) {
182           String[] zkservers = zkserver.split(",");
183 
184           if (zkservers.length > 1) {
185             // In local mode deployment, we have the master + a region server and zookeeper server
186             // started in the same process. Therefore, we only support one zookeeper server.
187             String errorMsg = "Could not start ZK with " + zkservers.length +
188                 " ZK servers in local mode deployment. Aborting as clients (e.g. shell) will not "
189                 + "be able to find this ZK quorum.";
190               System.err.println(errorMsg);
191               throw new IOException(errorMsg);
192           }
193 
194           String[] parts = zkservers[0].split(":");
195 
196           if (parts.length == 2) {
197             // the second part is the client port
198             zkClientPort = Integer.parseInt(parts [1]);
199           }
200         }
201         // If the client port could not be find in server quorum conf, try another conf
202         if (zkClientPort == 0) {
203           zkClientPort = conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 0);
204           // The client port has to be set by now; if not, throw exception.
205           if (zkClientPort == 0) {
206             throw new IOException("No config value for " + HConstants.ZOOKEEPER_CLIENT_PORT);
207           }
208         }
209         zooKeeperCluster.setDefaultClientPort(zkClientPort);
210         // set the ZK tick time if specified
211         int zkTickTime = conf.getInt(HConstants.ZOOKEEPER_TICK_TIME, 0);
212         if (zkTickTime > 0) {
213           zooKeeperCluster.setTickTime(zkTickTime);
214         }
215 
216         // login the zookeeper server principal (if using security)
217         ZKUtil.loginServer(conf, HConstants.ZK_SERVER_KEYTAB_FILE,
218           HConstants.ZK_SERVER_KERBEROS_PRINCIPAL, null);
219         int localZKClusterSessionTimeout =
220           conf.getInt(HConstants.ZK_SESSION_TIMEOUT + ".localHBaseCluster", 10*1000);
221         conf.setInt(HConstants.ZK_SESSION_TIMEOUT, localZKClusterSessionTimeout);
222         LOG.info("Starting a zookeeper cluster");
223         int clientPort = zooKeeperCluster.startup(zkDataPath);
224         if (clientPort != zkClientPort) {
225           String errorMsg = "Could not start ZK at requested port of " +
226             zkClientPort + ".  ZK was started at port: " + clientPort +
227             ".  Aborting as clients (e.g. shell) will not be able to find " +
228             "this ZK quorum.";
229           System.err.println(errorMsg);
230           throw new IOException(errorMsg);
231         }
232         conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, Integer.toString(clientPort));
233 
234         // Need to have the zk cluster shutdown when master is shutdown.
235         // Run a subclass that does the zk cluster shutdown on its way out.
236         int mastersCount = conf.getInt("hbase.masters", 1);
237         int regionServersCount = conf.getInt("hbase.regionservers", 1);
238         // Set start timeout to 5 minutes for cmd line start operations
239         conf.setIfUnset("hbase.master.start.timeout.localHBaseCluster", "300000");
240         LOG.info("Starting up instance of localHBaseCluster; master=" + mastersCount +
241           ", regionserversCount=" + regionServersCount);
242         LocalHBaseCluster cluster = new LocalHBaseCluster(conf, mastersCount, regionServersCount,
243           LocalHMaster.class, HRegionServer.class);
244         ((LocalHMaster)cluster.getMaster(0)).setZKCluster(zooKeeperCluster);
245         cluster.startup();
246         waitOnMasterThreads(cluster);
247       } else {
248         logProcessInfo(getConf());
249         CoordinatedStateManager csm =
250           CoordinatedStateManagerFactory.getCoordinatedStateManager(conf);
251         HMaster master = HMaster.constructMaster(masterClass, conf, csm);
252         if (master.isStopped()) {
253           LOG.info("Won't bring the Master up as a shutdown is requested");
254           return 1;
255         }
256         master.start();
257         master.join();
258         if(master.isAborted())
259           throw new RuntimeException("HMaster Aborted");
260       }
261     } catch (Throwable t) {
262       LOG.error("Master exiting", t);
263       return 1;
264     }
265     return 0;
266   }
267 
268   @SuppressWarnings("resource")
269   private int stopMaster() {
270     Admin adm = null;
271     try {
272       Configuration conf = getConf();
273       // Don't try more than once
274       conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
275       adm = new HBaseAdmin(getConf());
276       adm.shutdown();
277     } catch (MasterNotRunningException e) {
278       LOG.error("Master not running");
279       return 1;
280     } catch (ZooKeeperConnectionException e) {
281       LOG.error("ZooKeeper not available");
282       return 1;
283     } catch (IOException e) {
284       LOG.error("Got IOException: " +e.getMessage(), e);
285       return 1;
286     } catch (Throwable t) {
287       LOG.error("Failed to stop master", t);
288       return 1;
289     } finally {
290       if (adm != null) {
291         try {
292           adm.close();
293         } catch (Throwable t) {
294           LOG.error("Failed to close Admin", t);
295           return 1;
296         }
297       }
298     }
299     return 0;
300   }
301 
302   private void waitOnMasterThreads(LocalHBaseCluster cluster) throws InterruptedException{
303     List<JVMClusterUtil.MasterThread> masters = cluster.getMasters();
304     List<JVMClusterUtil.RegionServerThread> regionservers = cluster.getRegionServers();
305 
306     if (masters != null) {
307       for (JVMClusterUtil.MasterThread t : masters) {
308         t.join();
309         if(t.getMaster().isAborted()) {
310           closeAllRegionServerThreads(regionservers);
311           throw new RuntimeException("HMaster Aborted");
312         }
313       }
314     }
315   }
316 
317   private static void closeAllRegionServerThreads(
318       List<JVMClusterUtil.RegionServerThread> regionservers) {
319     for(JVMClusterUtil.RegionServerThread t : regionservers){
320       t.getRegionServer().stop("HMaster Aborted; Bringing down regions servers");
321     }
322   }
323 
324   /*
325    * Version of master that will shutdown the passed zk cluster on its way out.
326    */
327   public static class LocalHMaster extends HMaster {
328     private MiniZooKeeperCluster zkcluster = null;
329 
330     public LocalHMaster(Configuration conf, CoordinatedStateManager csm)
331     throws IOException, KeeperException, InterruptedException {
332       super(conf, csm);
333     }
334 
335     @Override
336     public void run() {
337       super.run();
338       if (this.zkcluster != null) {
339         try {
340           this.zkcluster.shutdown();
341         } catch (IOException e) {
342           e.printStackTrace();
343         }
344       }
345     }
346 
347     void setZKCluster(final MiniZooKeeperCluster zkcluster) {
348       this.zkcluster = zkcluster;
349     }
350   }
351 }