[源码解析] elastic search 8.0.0 的启动过程(一)

启动的时候刚开始没有做啥,真正开始的执行是从这个方法开始的
org.elasticsearch.cli.Command#execute

1、创建Environment

会利用到elasticsearch home中conf的配置文件,必填项

在创建Environment之前先准备

核心的关键是获取命令行传入进去的path.home的值,放到setting里。因为在创建Environment的时候,要依据该参数将里面的

config、plugins、data、logs、bin、lib、modules等解析出来,正好对应相应文件夹

xiaohuihui@xiaohuihuideMBP 8_home % ls
config  data    lib     logs    modules plugins

相当于从path.home里解析相应路径,这个时候会有一个Environment的变量,这个变量还不是最终返回的Environment,因为还没解析配置文件elasticsearch.yaml。

接着开始解析elasticsearch.yaml文件,如果用户在该配置文件中设置了一些logs、data的路径,才会是最终的路径,因为解析完该配置文件后,es会new一个Environment 返回,这时的logs、data等的路径是解析完elasticsearch.yaml之后的。总结一下,es本身对于logs、data等有默认的路径,如果用户通过elasticsearch.yaml进行了设置,就使用用户设置的。

2、init

2.1 首先根据上文传下来的setting又创建了一个Environment,(为啥不知道)

2.2 接着开始配置log。还是依据环境中的log路径

加载的log plugin名字叫org.elasticsearch.common.logging。

和log相关的配置文件为log4j2.properties,es会加载该文件并解析里面的配置

默认log的level是Level.ERROR,但是通过logger.level配置,如果进行了设置会对默认值进行覆盖,所以也是可以调整该默认值的

2.3 检查Lucene的版本是否正确

2.4 开始处理modules模块

共49个。每一个都被封装为PluginInfo对象

但是并不做其他处理,只有一个符合条件作为进程被start

2.5 接着检查和设置系统的一些资源

比如不能是root用户在操作

如果是Linux平台尝试申请最大数量的线程数,就是申请开线程的时候不会受到数量的限制。

2.6 为Environment初始SecurityManager

es自定义了ESPolicy,并启动SecurityManager.(没看懂)

3、开始创建Node对象

Node表示的是集群中的一个节点,此时的setting信息

{"client.type":"node","cluster.name":"elasticsearch","node.name":null,"path.home":"/Users/xiaohuihui/Downloads/elasticsearch-master/build/elasticsearch-distros/extracted_elasticsearch_8.0.0-SNAPSHOT_archive_darwin_default/elasticsearch-8.0.0-SNAPSHOT","path.logs":"/Users/xiaohuihui/Downloads/elasticsearch-master/build/elasticsearch-distros/extracted_elasticsearch_8.0.0-SNAPSHOT_archive_darwin_default/elasticsearch-8.0.0-SNAPSHOT/logs"}

这个setting有什么用呢?在下面有些场景进行判断的时候会用到。

3.1 把对modules和plugin的处理封装为一个叫做PluginsService的对象,创建它的过程就是加载module和plugin的过程。创建完成后继续返回到Node的创建过程,并把PluginsService对象赋值给Node中的一个变量,接着就是将这些插件的角色抽取出来,放到内存中,使用叫做roleMap的Map保存

3.2 创建NodeEnvironment。它指的是es home中data的路径,因为data文件夹下还要存放一些和索引相关的文件等。

这里的NodeEnvironment指的就是红色框框出来的内容。

同时会检查对文件夹是否有写入权限,是否有原子移动权限

会按照data的路径将磁盘上的文件加载到内存中,封装成NodeMetadata对象,这个对象是什么意思呢。它存在于当前节点的data文件夹中,如果es实例重复启动,它依旧会存在。这个是可以验证出来的。当你启动es的时候,如果上次你进行过操作,会发现data文件夹中是有记录的。如果第一次启动es,data文件夹是空的。如果该对象有值,就如下面所示

NodeMetadata{nodeId='zTVfnC6sRReXE9mbtqd6Aw', nodeVersion=8.0.0}

这样NodeEnvironment就创建完成了。node对象使用引用nodeEnvironment指向它。

接下来又创建了一个对象LocalNodeFactory,根据名字是本地节点工厂,不过是依据nodeId和setting构建的,暂时还没看到到如何发挥作用

接下来创建了一个ThreadPool对象,不要被它的名字迷惑,这里可不是创建了一个线程池,而是创建了好几个线程池。具体创建了多少个呢?27个,而且每个线程池都有自己的名字,对每一个模块都创建一个线程池,其实正常我们的业务系统中也是这样使用的,不可能全局共用一个,而且每个模块用自己的,互不干扰。es也是如此

而内部类ExecutorHolder才是我们熟知的线程池,我们看它的构造方法

static class ExecutorHolder {
        private final ExecutorService executor;
        public final Info info;

        ExecutorHolder(ExecutorService executor, Info info) {}

就更确定了这一点

不过毕竟是对线程池做了封装,es对线程池也是分类型的,

DIRECT("direct"),
FIXED("fixed"),
FIXED_AUTO_QUEUE_SIZE("fixed_auto_queue_size"), // TODO: remove in 9.0
SCALING("scaling");

fixed和scaling的差别主要是在线程数上

而在构建Node的整个过程中是如何处理资源的释放的呢?

这里的资源释放指的是读取磁盘数据的IO请求,创建线程池等内存线程资源,使用一个list管理。在代码继续往下走的过程中收集那些在出现异常情况回收的资源,而不是每个需要回收的资源的try finally等代码块,比如

resourcesToClose.add(() -> ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS));

resourcesToClose.add(() -> HeaderWarning.removeThreadContext(threadPool.getThreadContext()));

关注公众号,帮忙涨个粉

猜你喜欢

转载自blog.csdn.net/weixin_39394909/article/details/108307481