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.classification.InterfaceAudience;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.fs.FileSystem;
34  import org.apache.hadoop.hbase.CoordinatedStateManager;
35  import org.apache.hadoop.hbase.CoordinatedStateManagerFactory;
36  import org.apache.hadoop.hbase.MasterNotRunningException;
37  import org.apache.hadoop.hbase.ZNodeClearer;
38  import org.apache.hadoop.hbase.HConstants;
39  import org.apache.hadoop.hbase.LocalHBaseCluster;
40  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
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";
65  
66    private final Class<? extends HMaster> masterClass;
67  
68    public HMasterCommandLine(Class<? extends HMaster> masterClass) {
69      this.masterClass = masterClass;
70    }
71  
72    protected String getUsage() {
73      return USAGE;
74    }
75  
76  
77    public int run(String args[]) throws Exception {
78      Options opt = new Options();
79      opt.addOption("localRegionServers", true,
80        "RegionServers to start in master process when running standalone");
81      opt.addOption("masters", true, "Masters to start in this process");
82      opt.addOption("minRegionServers", true, "Minimum RegionServers needed to host user tables");
83      opt.addOption("backup", false, "Do not try to become HMaster until the primary fails");
84  
85      CommandLine cmd;
86      try {
87        cmd = new GnuParser().parse(opt, args);
88      } catch (ParseException e) {
89        LOG.error("Could not parse: ", e);
90        usage(null);
91        return 1;
92      }
93  
94  
95      if (cmd.hasOption("minRegionServers")) {
96        String val = cmd.getOptionValue("minRegionServers");
97        getConf().setInt("hbase.regions.server.count.min",
98                    Integer.valueOf(val));
99        LOG.debug("minRegionServers set to " + val);
100     }
101 
102     // minRegionServers used to be minServers.  Support it too.
103     if (cmd.hasOption("minServers")) {
104       String val = cmd.getOptionValue("minServers");
105       getConf().setInt("hbase.regions.server.count.min",
106                   Integer.valueOf(val));
107       LOG.debug("minServers set to " + val);
108     }
109 
110     // check if we are the backup master - override the conf if so
111     if (cmd.hasOption("backup")) {
112       getConf().setBoolean(HConstants.MASTER_TYPE_BACKUP, true);
113     }
114 
115     // How many regionservers to startup in this process (we run regionservers in same process as
116     // master when we are in local/standalone mode. Useful testing)
117     if (cmd.hasOption("localRegionServers")) {
118       String val = cmd.getOptionValue("localRegionServers");
119       getConf().setInt("hbase.regionservers", Integer.valueOf(val));
120       LOG.debug("localRegionServers set to " + val);
121     }
122     // How many masters to startup inside this process; useful testing
123     if (cmd.hasOption("masters")) {
124       String val = cmd.getOptionValue("masters");
125       getConf().setInt("hbase.masters", Integer.valueOf(val));
126       LOG.debug("masters set to " + val);
127     }
128 
129     @SuppressWarnings("unchecked")
130     List<String> remainingArgs = cmd.getArgList();
131     if (remainingArgs.size() != 1) {
132       usage(null);
133       return 1;
134     }
135 
136     String command = remainingArgs.get(0);
137 
138     if ("start".equals(command)) {
139       return startMaster();
140     } else if ("stop".equals(command)) {
141       return stopMaster();
142     } else if ("clear".equals(command)) {
143       return (ZNodeClearer.clear(getConf()) ? 0 : 1);
144     } else {
145       usage("Invalid command: " + command);
146       return 1;
147     }
148   }
149 
150   private int startMaster() {
151     Configuration conf = getConf();
152     try {
153       // If 'local', defer to LocalHBaseCluster instance.  Starts master
154       // and regionserver both in the one JVM.
155       if (LocalHBaseCluster.isLocal(conf)) {
156         DefaultMetricsSystem.setMiniClusterMode(true);
157         conf.setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 1);
158         final MiniZooKeeperCluster zooKeeperCluster = new MiniZooKeeperCluster(conf);
159         File zkDataPath = new File(conf.get(HConstants.ZOOKEEPER_DATA_DIR));
160         int zkClientPort = conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 0);
161         if (zkClientPort == 0) {
162           throw new IOException("No config value for "
163               + HConstants.ZOOKEEPER_CLIENT_PORT);
164         }
165         zooKeeperCluster.setDefaultClientPort(zkClientPort);
166 
167         // login the zookeeper server principal (if using security)
168         ZKUtil.loginServer(conf, "hbase.zookeeper.server.keytab.file",
169           "hbase.zookeeper.server.kerberos.principal", null);
170 
171         int clientPort = zooKeeperCluster.startup(zkDataPath);
172         if (clientPort != zkClientPort) {
173           String errorMsg = "Could not start ZK at requested port of " +
174             zkClientPort + ".  ZK was started at port: " + clientPort +
175             ".  Aborting as clients (e.g. shell) will not be able to find " +
176             "this ZK quorum.";
177           System.err.println(errorMsg);
178           throw new IOException(errorMsg);
179         }
180         conf.set(HConstants.ZOOKEEPER_CLIENT_PORT,
181                  Integer.toString(clientPort));
182         conf.setInt(HConstants.ZK_SESSION_TIMEOUT, 10 *1000);
183         // Need to have the zk cluster shutdown when master is shutdown.
184         // Run a subclass that does the zk cluster shutdown on its way out.
185         LocalHBaseCluster cluster = new LocalHBaseCluster(conf, conf.getInt("hbase.masters", 1),
186           conf.getInt("hbase.regionservers", 0), LocalHMaster.class, HRegionServer.class);
187         ((LocalHMaster)cluster.getMaster(0)).setZKCluster(zooKeeperCluster);
188         cluster.startup();
189         waitOnMasterThreads(cluster);
190       } else {
191         logProcessInfo(getConf());
192         CoordinatedStateManager csm =
193           CoordinatedStateManagerFactory.getCoordinatedStateManager(conf);
194         HMaster master = HMaster.constructMaster(masterClass, conf, csm);
195         if (master.isStopped()) {
196           LOG.info("Won't bring the Master up as a shutdown is requested");
197           return 1;
198         }
199         master.start();
200         master.join();
201         if(master.isAborted())
202           throw new RuntimeException("HMaster Aborted");
203       }
204     } catch (Throwable t) {
205       LOG.error("Master exiting", t);
206       return 1;
207     }
208     return 0;
209   }
210 
211   private int stopMaster() {
212     HBaseAdmin adm = null;
213     try {
214       Configuration conf = getConf();
215       // Don't try more than once
216       conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
217       adm = new HBaseAdmin(getConf());
218     } catch (MasterNotRunningException e) {
219       LOG.error("Master not running");
220       return 1;
221     } catch (ZooKeeperConnectionException e) {
222       LOG.error("ZooKeeper not available");
223       return 1;
224     } catch (IOException e) {
225       LOG.error("Got IOException: " +e.getMessage(), e);
226       return 1;
227     }
228     try {
229       adm.shutdown();
230     } catch (Throwable t) {
231       LOG.error("Failed to stop master", t);
232       return 1;
233     }
234     return 0;
235   }
236 
237   private void waitOnMasterThreads(LocalHBaseCluster cluster) throws InterruptedException{
238     List<JVMClusterUtil.MasterThread> masters = cluster.getMasters();
239     List<JVMClusterUtil.RegionServerThread> regionservers = cluster.getRegionServers();
240 
241     if (masters != null) {
242       for (JVMClusterUtil.MasterThread t : masters) {
243         t.join();
244         if(t.getMaster().isAborted()) {
245           closeAllRegionServerThreads(regionservers);
246           throw new RuntimeException("HMaster Aborted");
247         }
248       }
249     }
250   }
251 
252   private static void closeAllRegionServerThreads(List<JVMClusterUtil.RegionServerThread> regionservers) {
253     for(JVMClusterUtil.RegionServerThread t : regionservers){
254       t.getRegionServer().stop("HMaster Aborted; Bringing down regions servers");
255     }
256   }
257 
258   /*
259    * Version of master that will shutdown the passed zk cluster on its way out.
260    */
261   public static class LocalHMaster extends HMaster {
262     private MiniZooKeeperCluster zkcluster = null;
263 
264     public LocalHMaster(Configuration conf, CoordinatedStateManager csm)
265     throws IOException, KeeperException, InterruptedException {
266       super(conf, csm);
267     }
268 
269     @Override
270     public void run() {
271       super.run();
272       if (this.zkcluster != null) {
273         try {
274           this.zkcluster.shutdown();
275         } catch (IOException e) {
276           e.printStackTrace();
277         }
278       }
279     }
280 
281     void setZKCluster(final MiniZooKeeperCluster zkcluster) {
282       this.zkcluster = zkcluster;
283     }
284   }
285 }