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 19 package org.apache.zookeeper.server; 20 21 import java.io.IOException; 22 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.TimeUnit; 24 import javax.management.JMException; 25 import org.apache.yetus.audience.InterfaceAudience; 26 import org.apache.zookeeper.audit.ZKAuditProvider; 27 import org.apache.zookeeper.jmx.ManagedUtil; 28 import org.apache.zookeeper.metrics.MetricsProvider; 29 import org.apache.zookeeper.metrics.MetricsProviderLifeCycleException; 30 import org.apache.zookeeper.metrics.impl.MetricsProviderBootstrap; 31 import org.apache.zookeeper.server.admin.AdminServer; 32 import org.apache.zookeeper.server.admin.AdminServer.AdminServerException; 33 import org.apache.zookeeper.server.admin.AdminServerFactory; 34 import org.apache.zookeeper.server.auth.ProviderRegistry; 35 import org.apache.zookeeper.server.persistence.FileTxnSnapLog; 36 import org.apache.zookeeper.server.persistence.FileTxnSnapLog.DatadirException; 37 import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException; 38 import org.apache.zookeeper.server.util.JvmPauseMonitor; 39 import org.apache.zookeeper.util.ServiceUtils; 40 import org.slf4j.Logger; 41 import org.slf4j.LoggerFactory; 42 43 /** 44 * This class starts and runs a standalone ZooKeeperServer. 45 */ 46 @InterfaceAudience.Public 47 public class ZooKeeperServerMain { 48 49 private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperServerMain.class); 50 51 private static final String USAGE = "Usage: ZooKeeperServerMain configfile | port datadir [ticktime] [maxcnxns]"; 52 53 // ZooKeeper server supports two kinds of connection: unencrypted and encrypted. 54 private ServerCnxnFactory cnxnFactory; 55 private ServerCnxnFactory secureCnxnFactory; 56 private ContainerManager containerManager; 57 private MetricsProvider metricsProvider; 58 private AdminServer adminServer; 59 60 /* 61 * Start up the ZooKeeper server. 62 * 63 * @param args the configfile or the port datadir [ticktime] 64 */ main(String[] args)65 public static void main(String[] args) { 66 ZooKeeperServerMain main = new ZooKeeperServerMain(); 67 try { 68 main.initializeAndRun(args); 69 } catch (IllegalArgumentException e) { 70 LOG.error("Invalid arguments, exiting abnormally", e); 71 LOG.info(USAGE); 72 System.err.println(USAGE); 73 ZKAuditProvider.addServerStartFailureAuditLog(); 74 ServiceUtils.requestSystemExit(ExitCode.INVALID_INVOCATION.getValue()); 75 } catch (ConfigException e) { 76 LOG.error("Invalid config, exiting abnormally", e); 77 System.err.println("Invalid config, exiting abnormally"); 78 ZKAuditProvider.addServerStartFailureAuditLog(); 79 ServiceUtils.requestSystemExit(ExitCode.INVALID_INVOCATION.getValue()); 80 } catch (DatadirException e) { 81 LOG.error("Unable to access datadir, exiting abnormally", e); 82 System.err.println("Unable to access datadir, exiting abnormally"); 83 ZKAuditProvider.addServerStartFailureAuditLog(); 84 ServiceUtils.requestSystemExit(ExitCode.UNABLE_TO_ACCESS_DATADIR.getValue()); 85 } catch (AdminServerException e) { 86 LOG.error("Unable to start AdminServer, exiting abnormally", e); 87 System.err.println("Unable to start AdminServer, exiting abnormally"); 88 ZKAuditProvider.addServerStartFailureAuditLog(); 89 ServiceUtils.requestSystemExit(ExitCode.ERROR_STARTING_ADMIN_SERVER.getValue()); 90 } catch (Exception e) { 91 LOG.error("Unexpected exception, exiting abnormally", e); 92 ZKAuditProvider.addServerStartFailureAuditLog(); 93 ServiceUtils.requestSystemExit(ExitCode.UNEXPECTED_ERROR.getValue()); 94 } 95 LOG.info("Exiting normally"); 96 ServiceUtils.requestSystemExit(ExitCode.EXECUTION_FINISHED.getValue()); 97 } 98 initializeAndRun(String[] args)99 protected void initializeAndRun(String[] args) throws ConfigException, IOException, AdminServerException { 100 try { 101 ManagedUtil.registerLog4jMBeans(); 102 } catch (JMException e) { 103 LOG.warn("Unable to register log4j JMX control", e); 104 } 105 106 ServerConfig config = new ServerConfig(); 107 if (args.length == 1) { 108 config.parse(args[0]); 109 } else { 110 config.parse(args); 111 } 112 113 runFromConfig(config); 114 } 115 116 /** 117 * Run from a ServerConfig. 118 * @param config ServerConfig to use. 119 * @throws IOException 120 * @throws AdminServerException 121 */ runFromConfig(ServerConfig config)122 public void runFromConfig(ServerConfig config) throws IOException, AdminServerException { 123 LOG.info("Starting server"); 124 FileTxnSnapLog txnLog = null; 125 try { 126 try { 127 metricsProvider = MetricsProviderBootstrap.startMetricsProvider( 128 config.getMetricsProviderClassName(), 129 config.getMetricsProviderConfiguration()); 130 } catch (MetricsProviderLifeCycleException error) { 131 throw new IOException("Cannot boot MetricsProvider " + config.getMetricsProviderClassName(), error); 132 } 133 ServerMetrics.metricsProviderInitialized(metricsProvider); 134 ProviderRegistry.initialize(); 135 // Note that this thread isn't going to be doing anything else, 136 // so rather than spawning another thread, we will just call 137 // run() in this thread. 138 // create a file logger url from the command line args 139 txnLog = new FileTxnSnapLog(config.dataLogDir, config.dataDir); 140 JvmPauseMonitor jvmPauseMonitor = null; 141 if (config.jvmPauseMonitorToRun) { 142 jvmPauseMonitor = new JvmPauseMonitor(config); 143 } 144 final ZooKeeperServer zkServer = new ZooKeeperServer(jvmPauseMonitor, txnLog, config.tickTime, config.minSessionTimeout, config.maxSessionTimeout, config.listenBacklog, null, config.initialConfig); 145 txnLog.setServerStats(zkServer.serverStats()); 146 147 // Registers shutdown handler which will be used to know the 148 // server error or shutdown state changes. 149 final CountDownLatch shutdownLatch = new CountDownLatch(1); 150 zkServer.registerServerShutdownHandler(new ZooKeeperServerShutdownHandler(shutdownLatch)); 151 152 // Start Admin server 153 adminServer = AdminServerFactory.createAdminServer(); 154 adminServer.setZooKeeperServer(zkServer); 155 adminServer.start(); 156 157 boolean needStartZKServer = true; 158 if (config.getClientPortAddress() != null) { 159 cnxnFactory = ServerCnxnFactory.createFactory(); 160 cnxnFactory.configure(config.getClientPortAddress(), config.getMaxClientCnxns(), config.getClientPortListenBacklog(), false); 161 cnxnFactory.startup(zkServer); 162 // zkServer has been started. So we don't need to start it again in secureCnxnFactory. 163 needStartZKServer = false; 164 } 165 if (config.getSecureClientPortAddress() != null) { 166 secureCnxnFactory = ServerCnxnFactory.createFactory(); 167 secureCnxnFactory.configure(config.getSecureClientPortAddress(), config.getMaxClientCnxns(), config.getClientPortListenBacklog(), true); 168 secureCnxnFactory.startup(zkServer, needStartZKServer); 169 } 170 171 containerManager = new ContainerManager( 172 zkServer.getZKDatabase(), 173 zkServer.firstProcessor, 174 Integer.getInteger("znode.container.checkIntervalMs", (int) TimeUnit.MINUTES.toMillis(1)), 175 Integer.getInteger("znode.container.maxPerMinute", 10000), 176 Long.getLong("znode.container.maxNeverUsedIntervalMs", 0) 177 ); 178 containerManager.start(); 179 ZKAuditProvider.addZKStartStopAuditLog(); 180 181 // Watch status of ZooKeeper server. It will do a graceful shutdown 182 // if the server is not running or hits an internal error. 183 shutdownLatch.await(); 184 185 shutdown(); 186 187 if (cnxnFactory != null) { 188 cnxnFactory.join(); 189 } 190 if (secureCnxnFactory != null) { 191 secureCnxnFactory.join(); 192 } 193 if (zkServer.canShutdown()) { 194 zkServer.shutdown(true); 195 } 196 } catch (InterruptedException e) { 197 // warn, but generally this is ok 198 LOG.warn("Server interrupted", e); 199 } finally { 200 if (txnLog != null) { 201 txnLog.close(); 202 } 203 if (metricsProvider != null) { 204 try { 205 metricsProvider.stop(); 206 } catch (Throwable error) { 207 LOG.warn("Error while stopping metrics", error); 208 } 209 } 210 } 211 } 212 213 /** 214 * Shutdown the serving instance 215 */ shutdown()216 protected void shutdown() { 217 if (containerManager != null) { 218 containerManager.stop(); 219 } 220 if (cnxnFactory != null) { 221 cnxnFactory.shutdown(); 222 } 223 if (secureCnxnFactory != null) { 224 secureCnxnFactory.shutdown(); 225 } 226 try { 227 if (adminServer != null) { 228 adminServer.shutdown(); 229 } 230 } catch (AdminServerException e) { 231 LOG.warn("Problem stopping AdminServer", e); 232 } 233 } 234 235 // VisibleForTesting getCnxnFactory()236 ServerCnxnFactory getCnxnFactory() { 237 return cnxnFactory; 238 } 239 240 // VisibleForTesting getSecureCnxnFactory()241 ServerCnxnFactory getSecureCnxnFactory() { 242 return secureCnxnFactory; 243 } 244 245 /** 246 * Shutdowns properly the service, this method is not a public API. 247 */ close()248 public void close() { 249 ServerCnxnFactory primaryCnxnFactory = this.cnxnFactory; 250 if (primaryCnxnFactory == null) { 251 // in case of pure TLS we can hook into secureCnxnFactory 252 primaryCnxnFactory = secureCnxnFactory; 253 } 254 if (primaryCnxnFactory == null || primaryCnxnFactory.getZooKeeperServer() == null) { 255 return; 256 } 257 ZooKeeperServerShutdownHandler zkShutdownHandler = primaryCnxnFactory.getZooKeeperServer().getZkShutdownHandler(); 258 zkShutdownHandler.handle(ZooKeeperServer.State.SHUTDOWN); 259 try { 260 // ServerCnxnFactory will call the shutdown 261 primaryCnxnFactory.join(); 262 } catch (InterruptedException ex) { 263 Thread.currentThread().interrupt(); 264 } 265 } 266 267 } 268