上一篇文章说了ES的源码编译以及如何在本地编译。这一篇文章主要说明ES的启动过程。
环境准备参考ElasticSearch源码编译和Debug。
说明:本文章使用的ES版本是:6.7.0
启动函数:org.elasticsearch.bootstrap.ElasticSearch
设置如下断点:
启动在上一篇文章中介绍的Debug模式中的一种,这里我用的远程Debug模式。
ElasticSearch的启动过程跟着Debug流程走一遍,可以看出ES启动流程大概分为以下几个阶段:
org.elasticsearch.bootstrap.Elasticsearch#main(java.lang.String[]) 解析命令参数,加载配置,权限验证org.elasticsearch.bootstrap.Bootstrap 初始化,资源检查org.elasticsearch.node.Node 启动单机节点,创建keepAlive线程
为创建Node对象做准备,并最终创建Node对象
创建Node对象
如何加载模块和插件创建模块和插件的线程池启动Node实例一、org.elasticsearch.bootstrap.Elasticsearch#main(java.lang.String[])解析命令参数,加载配置,权限验证程序入口代码如下:
如果通过启动命令传入了DNS Cache时间,则重写DNS Cache时间创建 SecurityManager 安全管理器
SecurityManager:安全管理器在Java语言中的作用就是检查操作是否有权限执行,通过则顺序进行,否则抛出一个异常LogConfigurator.registerErrorListener(); 注册错误日志监听器new Elasticsearch(); 创建 Elasticsearch 对象Elasticsearch类继承了EnvironmentAwareCommand、Command,其完整的继承关系如下所以Elasticsearch也可以解析命令行参数。
elasticsearch.main(args, terminal); 这里的main方法是其父类中的main方法,这里因为继承关系,方法执行的顺序如下:
org.elasticsearch.cli.Command#main 注册shutdownHook,当程序异常关闭时打印异常信息org.elasticsearch.cli.Command#mainWithoutErrorHandling 解析命令行参数org.elasticsearch.cli.EnvironmentAwareCommand#execute 加载配置路径:home、data、logsorg.elasticsearch.cli.EnvironmentAwareCommand#createEnv 加载elasticsearch.yaml配置文件,创建command运行的环境org.elasticsearch.bootstrap.Elasticsearch#execute 配置验证,进入Bootstrap.init阶段二、org.elasticsearch.bootstrap.Bootstrap 初始化,资源检查Bootstrap阶段做的事情比较多,主要方法如下:
/** * This method is invoked by {@link Elasticsearch#main(String[])} to startup elasticsearch. */ static void init( final boolean foreground, final Path pidFile, final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException { // force the class initializer for BootstrapInfo to run before // the security manager is installed BootstrapInfo.init(); INSTANCE = new Bootstrap(); final SecureSettings keystore = loadSecureSettings(initialEnv); final Environment environment = createEnvironment(foreground, pidFile, keystore, initialEnv.settings(), initialEnv.configFile()); if (Node.NODE_NAME_SETTING.exists(environment.settings())) { LogConfigurator.setNodeName(Node.NODE_NAME_SETTING.get(environment.settings())); } try { LogConfigurator.configure(environment); } catch (IOException e) { throw new BootstrapException(e); } if (environment.pidFile() != null) { try { PidFile.create(environment.pidFile(), true); } catch (IOException e) { throw new BootstrapException(e); } } final boolean closeStandardStreams = (foreground == false) || quiet; try { if (closeStandardStreams) { final Logger rootLogger = LogManager.getRootLogger(); final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class); if (maybeConsoleAppender != null) { Loggers.removeAppender(rootLogger, maybeConsoleAppender); } closeSystOut(); } // fail if somebody replaced the lucene jars checkLucene(); // install the default uncaught exception handler; must be done before security is // initialized as we do not want to grant the runtime permission // setDefaultUncaughtExceptionHandler Thread.setDefaultUncaughtExceptionHandler(new ElasticsearchUncaughtExceptionHandler()); INSTANCE.setup(true, environment); try { // any secure settings must be read during node construction IOUtils.close(keystore); } catch (IOException e) { throw new BootstrapException(e); } INSTANCE.start(); if (closeStandardStreams) { closeSysError(); } } catch (NodeValidationException | RuntimeException e) { // disable console logging, so user does not see the exception twice (jvm will show it already) final Logger rootLogger = LogManager.getRootLogger(); final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class); if (foreground && maybeConsoleAppender != null) { Loggers.removeAppender(rootLogger, maybeConsoleAppender); } Logger logger = LogManager.getLogger(Bootstrap.class); // HACK, it sucks to do this, but we will run users out of disk space otherwise if (e instanceof CreationException) { // guice: log the shortened exc to the log file ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = null; try { ps = new PrintStream(os, false, "UTF-8"); } catch (UnsupportedEncodingException uee) { assert false; e.addSuppressed(uee); } new StartupException(e).printStackTrace(ps); ps.flush(); try { logger.error("Guice Exception: {}", os.toString("UTF-8")); } catch (UnsupportedEncodingException uee) { assert false; e.addSuppressed(uee); } } else if (e instanceof NodeValidationException) { logger.error("node validation exception\n{}", e.getMessage()); } else { // full exception logger.error("Exception", e); } // re-enable it if appropriate, so they can see any logging during the shutdown process if (foreground && maybeConsoleAppender != null) { Loggers.addAppender(rootLogger, maybeConsoleAppender); } throw e; } }详细流程如下:
...