Node组装启动过程
elasticsearch的启动过程是根据配置和环境组装需要的模块并启动的过程。这一过程就是通过guice注入各个功能模块并启动这些模块,从而得到一个功能完整的node。正如之前所说elasticsearch的模块化特点,它的各个功能都是独立实现,然后实现通过guice对外提供。首先简单的说一下guice,它是google的一个轻量级依赖注入框架。它的作者也是依赖注入标准(JSR-330)制定者。虽然它是轻量级框架,但是它的功能及性能却非常好,这也是elasticsearch选用它作为代码主要框架的一个主要原因。它的使用请参考它的用户指导1
首先看一下node的初始化,node接口的唯一实现是InternalNode,它的初始化代码如下所示:
public InternalNode(Settings preparedSettings, boolean loadConfigSettings) throws ElasticsearchException {
final Settings pSettings = settingsBuilder().put(preparedSettings)
.put(Client.CLIENT_TYPE_SETTING, CLIENT_TYPE).build();
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(pSettings, loadConfigSettings);
tuple = new Tuple<>(TribeService.processSettings(tuple.v1()), tuple.v2());
logger.info("initializing ...");
//启动插件service,加载并启动插件
this.pluginsService = new PluginsService(tuple.v1(), tuple.v2());
this.settings = pluginsService.updatedSettings();
// create the environment based on the finalized (processed) view of the settings
this.environment = new Environment(this.settings());
CompressorFactory.configure(settings);
//配置node环境
final NodeEnvironment nodeEnvironment;
try {
nodeEnvironment = new NodeEnvironment(this.settings, this.environment);
} catch (IOException ex) {
throw new ElasticsearchIllegalStateException("Failed to created node environment", ex);
}
boolean success = false;
try {
//加载各个模块
ModulesBuilder modules = new ModulesBuilder();
modules.add(new Version.Module(version));
modules.add(new CacheRecyclerModule(settings));
modules.add(new PageCacheRecyclerModule(settings));
modules.add(new CircuitBreakerModule(settings));
modules.add(new BigArraysModule(settings));
modules.add(new PluginsModule(settings, pluginsService));
modules.add(new SettingsModule(settings));
modules.add(new NodeModule(this));
modules.add(new NetworkModule());
modules.add(new ScriptModule(settings));
modules.add(new EnvironmentModule(environment));
……
}
可以看到node的初始化过程主要包括三部分,第一是启动插件服务(es提供了插件功能来进行扩展功能,这也是它的一个亮点),加载需要的插件,第二是配置node环境,最后就是通过guice加载各个模块。接下来首先说一下启动各个模块的过程,插件服务稍微复杂最后再说。elasticsearch各个功能模块实现的非常好,解耦非常完美,很多模块都实现了生命周期接口,只有启动它才能够对外提供服务,它的启动过程也是功能模块初始化的过程。因此,node节点的启动过程也就是这些模块初始化的过程。如下面的代码片段所示:
public Node start() {
if (!lifecycle.moveToStarted()) {
return this;
}// hack around dependency injection problem (for now...)
injector.getInstance(Discovery.class).setAllocationService(injector.getInstance(AllocationService.class));
for (Class<? extends LifecycleComponent> plugin : pluginsService.services()) {
injector.getInstance(plugin).start();
}
//通过guice获取各个模块的service接口并启动
injector.getInstance(MappingUpdatedAction.class).start();
injector.getInstance(IndicesService.class).start();
injector.getInstance(IndexingMemoryController.class).start();
injector.getInstance(IndicesClusterStateService.class).start();
injector.getInstance(IndicesTTLService.class).start();
injector.getInstance(RiversManager.class).start();
injector.getInstance(SnapshotsService.class).start();
injector.getInstance(TransportService.class).start();
……
}
每个模块service都会实现一个start接口,模块功能初始化过程都是这这个函数中实现。每个模块的具体启动过程后面会有涉及,这里就不做深入分析。
最后着重说一下插件的加载过程。每个node在加载各个模块前,会首先加载所需要的插件,如果有些插件加载不成功node会启动失败。这里会加载三类插件:首先是配置插件,配置到节点配置文件中插件,如分词插件等;然后查找classpath中能找到的插件,这些插件一般防止在plugin文件夹中;最后是加载site插件,site插件是不涉及java代码的纯网站式插件,如监控插件head,bigdesk等。任何使用者都可以开发自己需要的插件,只要按着elasticsearch相关版本的插件开发规范来实现即可。
public PluginsService(Settings settings, Environment environment) {
super(settings);
this.environment = environment;
……
ImmutableList.Builder<Tuple<PluginInfo, Plugin>> tupleBuilder = ImmutableList.builder();
// 加载配置插件
String[] defaultPluginsClasses = settings.getAsArray("plugin.types");
for (String pluginClass : defaultPluginsClasses) {
Plugin plugin = loadPlugin(pluginClass, settings);
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), hasSite(plugin.name()), true, PluginInfo.VERSION_NOT_AVAILABLE);
if (logger.isTraceEnabled()) {
logger.trace("plugin loaded from settings [{}]", pluginInfo);
}
tupleBuilder.add(new Tuple<>(pluginInfo, plugin));
}
// 查找classpatch中的所有插件
loadPluginsIntoClassLoader();
if (loadClasspathPlugins) {
tupleBuilder.addAll(loadPluginsFromClasspath(settings));
}
this.plugins = tupleBuilder.build();
// We need to build a List of jvm and site plugins for checking mandatory plugins
Map<String, Plugin> jvmPlugins = Maps.newHashMap();
List<String> sitePlugins = Lists.newArrayList();
for (Tuple<PluginInfo, Plugin> tuple : this.plugins) {
jvmPlugins.put(tuple.v2().name(), tuple.v2());
if (tuple.v1().isSite()) {
sitePlugins.add(tuple.v1().getName());
}
}
// 加载site插件
ImmutableList<Tuple<PluginInfo, Plugin>> tuples = loadSitePlugins();
for (Tuple<PluginInfo, Plugin> tuple : tuples) {
sitePlugins.add(tuple.v1().getName());
}
// 检验代理插件,如果有加载不成功的插件就抛出异常,停止node启动。
String[] mandatoryPlugins = settings.getAsArray("plugin.mandatory", null);
if (mandatoryPlugins != null) {
Set<String> missingPlugins = Sets.newHashSet();
for (String mandatoryPlugin : mandatoryPlugins) {
if (!jvmPlugins.containsKey(mandatoryPlugin) && !sitePlugins.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
missingPlugins.add(mandatoryPlugin);
}
}
if (!missingPlugins.isEmpty()) {
throw new ElasticsearchException("Missing mandatory plugins [" + Strings.collectionToDelimitedString(missingPlugins, ", ") + "]");
}
}
……
}
以上就是pluginservice的初始化过程,在它的初始化过程中,加载所有能够找的插件。插件的启动在其他功能模块之前,些插件,如分词插件,启动不成功则会对节点的功能造成影响,因此会在这里就中断节点的启动过程让用户知道。
这就是节点的启动过程。插件加载成功,各个功能模块加载并启动成功,节点就启动成功。限于篇幅这里模块相关详情都没有进行深入在接下来模块分析中会一一分析。
Node组装启动过程的更多相关文章
- Openfire的启动过程与session管理
说明 本文源码基于Openfire4.0.2. Openfire的启动 Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openfire.jar包,并启动一个 ...
- spark1.4.1 启动过程
今天稍微没那么忙了,趁着这个时间,准备把spark的启动过程总结一下(),分享给大家.现在使用的spark1.4.1版本 当然前提是你已经把spark环境搭建好了. 1.我们启动spark的时候一般会 ...
- OGRE启动过程详解(OGRE HelloWorld程序原理解析)
本文介绍 OGRE 3D 1.9 程序的启动过程,即从程序启动到3D图形呈现,背后有哪些OGRE相关的代码被执行.会涉及的OGRE类包括: Root RenderSystem RenderWindow ...
- Android 启动过程总结
SystemServer的启动 frameworks/base/services/java/com/android/server/SystemServer.java: run() 其中调用Activi ...
- Android应用程序启动过程源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程 ...
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6629298 在前面一篇文章浅谈Android系 ...
- Android 启动过程的底层实现
转载请标明出处: http://blog.csdn.net/yujun411522/article/details/46367787 本文出自:[yujun411522的博客] 3.1 androi ...
- Android 应用程序启动过程源代码分析
本文转自:http://blog.csdn.net/luoshengyang/article/details/6689748 前文简要介绍了Android应用程序的Activity的启动过程.在And ...
- Nimbus<三>Storm源码分析--Nimbus启动过程
Nimbus server, 首先从启动命令开始, 同样是使用storm命令"storm nimbus”来启动看下源码, 此处和上面client不同, jvmtype="-serv ...
随机推荐
- css3 列表图片hover左右滚动效果
- word中添加Mathtype公式行间距改变问题
转载链接:http://blog.sciencenet.cn/home.php?mod=space&uid=471807&do=blog&id=616838 最近碰到在word ...
- 利用cvFindExtrinsicCameraParams2求取相机外参数
cvFindExtrinsicCameraParams2函数的定义: void cvFindExtrinsicCameraParams2( const CvMat* object_points, co ...
- UDP广播
客户端UDP发送消息至服务器端服务器IP:192.168.1.114服务器端口:2014 客户端 Socket socket = new Socket(AddressFamily.InterNetwo ...
- vim7.4官方源码在vs2013的编译方法及问题总结
vim7.4发布也有一段时候了,也该是把之前编译的7.3重新编译一下了,于是考虑着到最新的visual studio 2013编译一下,也顺便看看有没有其它问题. 1.安装vs2013,这个应该不用说 ...
- pwd---以绝对路径的方式显示用户当前工作目录
pwd命令以绝对路径的方式显示用户当前工作目录.命令将当前目录的全路径名称(从根目录)写入标准输出.全部目录使用/分隔.第一个/表示根目录,最后一个目录是当前目录.执行pwd命令可立刻得知您目前所在的 ...
- 【Henu ACM Round#18 C】Ilya and Sticks
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用cnt[i]记录数字i出现的次数就好. 然后i从1e6逆序到1 如果cnt[i+1]和cnt[i]>0同时成立的话. 那么得 ...
- 【Henu ACM Round #13 D】A Trivial Problem
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 123...n中末尾0的个数 只会由素因子2和5的个数决定且等于 Min{cnt[2],cnt[5]} 且素因子2的个数一定会比5多 ...
- ChinaVis2015 第一天会议
第二届 ChinaVis 2015 在天津举行,非常幸运发现者个会议,并在导师的带领下參与本次会议. 主要要是以可视化与可视分析为背景进行讲座,以马匡六为Speaker.袁晓如,张加万等致辞开幕式. ...
- LintCode 二叉树的遍历 (非递归)
前序: class Solution { public: /** * @param root: The root of binary tree. * @return: Preorder in vect ...