版权声明:本文为博主原创,转载请注明出处!
简介
本文主要解决以下问题:
1、启动ES的入口类及入口方法是哪个?
2、分析梳理ES服务启动的主要流程?
入口类
ES的入口类为org.elasticsearch.bootstrap.Elasticsearch
,启动方法为:
public static void main(final String[] args) throws Exception
该类通过继承EnvironmentAwareCommand类增加了CLI的支持,类图:
启动流程
Step 1、给JVM安装(临时的)安全管理器,并注册错误日志监听器。
ES在程序启动的第一步先给JVM安装了一个安全管理器,并授予了程序所有的权限(临时的,后续会更换新的安全管理器),以方便以后的操作。接下来会注册一个错误日志的监听器,来监听是否有错误发生,随后使用配置文件配置日志组件是会检查监听器是否检测到错误,如果有将通过抛异常的方式中止ES的启动过程。执行该动作的方法:
// org.elasticsearch.bootstrap.Elasticsearch
public static void main(final String[] args) throws Exception
Step 2、创建一个Elasticsearch类的实例(一个CLI的Command实例),并执行实例的main方法。
Elasticsearch类直接继承了EnvironmentAwareCommand,可以认为这一步创建了一个CLI的command对象。在该类的构造方法以及父类中定义了该
command
对象可以接受的cli的参数。执行该动作的方法:
// org.elasticsearch.bootstrap.Elasticsearch
public static void main(final String[] args) throws Exception
在
bin
目录下运行Elasticsearch -h
命令,可以查看该实例支持的所有命令行参数:
Step 3、添加JVM关闭的构造,使用默认配置配置日志组件。
为JVM添加了一个shutdown的钩子函数,在钩子函数中调用了close()方法。使用系统属性
es.logger.level
的值来配置日志组件,如果没有该配置则使用默认的INFO
级别来配置logger.level
。执行该动作的方法:
// org.elasticsearch.cli.Command
public final int main(String[] args, Terminal terminal) throws Exception
Step 4、解析help
、silent
、verbose
或normal
的参数配置,并输出或设置到Terminal
上。
首先检查控制台是否传入了
-h
或--help
参数,如果有的话打印帮助信息,并结束ES的启动过程。否则,依次检查-s
、-v
等参数,并根据相应的参数配置terminal
的信息输出方式。执行该动作的方法:
// org.elasticsearch.cli.Command
void mainWithoutErrorHandling(String[] args, Terminal terminal) throws Exception
Step 5、解析通过控制台传入的ES的配置参数,并根据配置参数创建Environment对象。
首先,解析通过控制台
-E
参数传入的ES配置。其次,通过System Property
补齐某些确实的配置。这两个过程都会对配置的key进行查重。解析配置的代码:
// org.elasticsearch.cli.EnvironmentAwareCommand
protected void execute(Terminal terminal, OptionSet options) throws Exception {
final Map<String, String> settings = new HashMap<>();
for (final KeyValuePair kvp : settingOption.values(options)) {
if (kvp.value.isEmpty()) {
throw new UserException(ExitCodes.USAGE, "setting [" + kvp.key + "] must not be empty");
}
if (settings.containsKey(kvp.key)) {
final String message = String.format(
Locale.ROOT,
"setting [%s] already set, saw [%s] and [%s]",
kvp.key,
settings.get(kvp.key),
kvp.value);
throw new UserException(ExitCodes.USAGE, message);
}
settings.put(kvp.key, kvp.value);
}
putSystemPropertyIfSettingIsMissing(settings, "default.path.conf", "es.default.path.conf");
putSystemPropertyIfSettingIsMissing(settings, "default.path.data", "es.default.path.data");
putSystemPropertyIfSettingIsMissing(settings, "default.path.logs", "es.default.path.logs");
putSystemPropertyIfSettingIsMissing(settings, "path.conf", "es.path.conf");
putSystemPropertyIfSettingIsMissing(settings, "path.data", "es.path.data");
putSystemPropertyIfSettingIsMissing(settings, "path.home", "es.path.home");
putSystemPropertyIfSettingIsMissing(settings, "path.logs", "es.path.logs");
execute(terminal, options, createEnv(terminal, settings));
}
接下来,根据解析到的配置项来创建Environment对象。
// org.elasticsearch.cli.EnvironmentAwareCommand
protected Environment createEnv(Terminal terminal, Map<String, String> settings) {
return InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings);
}
最终,通过InternalSettingsPreparer对象的prepareEnironment方法来创建Enironment对象。
// org.elasticsearch.node.InternalSettingsPreparer
public static Environment prepareEnvironment(Settings input, Terminal terminal, Map<String, String> properties)
该方法会合并控制台传入的配置项、部分通过系统环境变量设置的配置项及
elasticsearch.yml
设置的配置项。最终创建一个Environment对象,该对象中保存了ES程序的配置目录、数据目录、插件目录及日志目录的地址。
Step 6、解析控制台传入的-v
、-d
、-p
及-q
等参数,并依据相应的参数初始化Bootstrap
。
首先,检查是否传入了
-v
参数,如果有该参数则打印ES的版本信息并退出。接下来解析-d
、-p
及-q
参数,并依据这些参数调用Bootstrap.init
。执行该动作的方法:
// org.elasticsearch.bootstrap.Elasticsearch
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException
void init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv)
Step 7、通过调用BootstrapInfo.init()
方法的方式来初始化BootstrapInfo
对象。
通过这个对象可以获取
JNA
是否可用、系统Memory Lock
是否可用等一些系统信息。执行该动作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 8、创建一个Bootstrap
实例,加载Secure Settings
,并结合原有的配置重新创建Environment
对象。
在
Bootstrap
实例中首先启动了一个keep alive
线程。结合SecureSettings
重新创建Environment
对象。依据env
中的配置文件配置日志组件,这时会检查是否有错误日志产生。接下来输出一些配置相关的日志,并按需创建pidFile
。执行该动作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 9、检查Lucene
的版本,设置 默认的未捕获异常的处理器 ,并开始配置新建的Bootstrap
实例。
首先,根据是否守护经常运行的方式按需关闭
SysOut
。接下来检查Lucene
库的版本是否匹配。最后,设置DefaultUncaughtExceptionHandler
。执行该动作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 10、设置NativePluginControllers
,初始化native
资源,初始化资源“探针”,checkJarHell
,再次设置系统安全管理器并新建Node
对象。
在这些过程中间还会检查老配置项
bootstrap.seccomp
和新配置项bootstrap.system_call_filter
都配置了的情况下是否产生了冲突。执行该动作的方法:
// org.elasticsearch.bootstrap.Bootstrap
private void setup(boolean addShutdownHook, Environment environment) throws BootstrapException
Step 11、关闭SecureSettings
的存储文件,并调用Bootstrap
对象的start
方法,按需closeSysError
。
这是启动流程的最后一步。