最近需要研究搜索的集群。由于大脑日渐萎缩,只好把代码记下来以供参考,好久没在csdn上写东西了,呵呵。
elasticsearch是一个基于lucene的搜索集群,关于lucene的介绍有如下参考:
Annotated-Lucene源码剖析中文版
Architecture and Implementation of Apache Lucene
Lucene 源码分析
elasticsesarch作为一个封装lucene的开源项目,根据CAP理论在牺牲一致性(C)的,保证了数据的分布(P)和可达(A)。当然数据是有最终一直性的。
参考资料:solar VS elk http://solr-vs-elasticsearch.com/
关于elasticsearch如何保证cap我们以后会深入理解。
本章先告诉大家如何看elasticsearch源代码:
如果你熟悉AOP 或者spring framework, 就会发现elasticsearch源代码是按照模块组织的。只不过用了另外一个开源框架Guice。guice如何实现依赖注入的参考:
http://malsup.com/jquery/media/guice.pdf
扯了很多终于可以讲主题了:
elasticsearch的官网:https://www.elastic.co/blog/found-elasticsearch-internals列出了所有elasticsearch 的模块。今天就已discovery module为例看看elasticsearch是如何注册并使用这一service的。
node.class代表elasticsearch的一个节点,他包含了启动一个节点的所有服务:`
Node(Settings preparedSettings, Version version, Collection> classpathPlugins) {
final Settings pSettings = settingsBuilder().put(preparedSettings)
.put(Client.CLIENT_TYPE_SETTING, CLIENT_TYPE).build();
Environment tmpEnv = InternalSettingsPreparer.prepareEnvironment(pSettings, null);
Settings tmpSettings = TribeService.processSettings(tmpEnv.settings());
ESLogger logger = Loggers.getLogger(Node.class, tmpSettings.get("name"));
logger.info("version[{}], pid[{}], build[{}/{}]", version, JvmInfo.jvmInfo().pid(), Build.CURRENT.hashShort(), Build.CURRENT.timestamp());
logger.info("initializing ...");
if (logger.isDebugEnabled()) {
logger.debug("using config [{}], data [{}], logs [{}], plugins [{}]",
tmpEnv.configFile(), Arrays.toString(tmpEnv.dataFiles()), tmpEnv.logsFile(), tmpEnv.pluginsFile());
}
this.pluginsService = new PluginsService(tmpSettings, tmpEnv.pluginsFile(), classpathPlugins);
this.settings = pluginsService.updatedSettings();
// create the environment based on the finalized (processed) view of the settings
this.environment = new Environment(this.settings());
final NodeEnvironment nodeEnvironment;
try {
nodeEnvironment = new NodeEnvironment(this.settings, this.environment);
} catch (IOException ex) {
throw new IllegalStateException("Failed to created node environment", ex);
}
final ThreadPool threadPool = new ThreadPool(settings);
boolean success = false;
try {
ModulesBuilder modules = new ModulesBuilder();
modules.add(new Version.Module(version));
modules.add(new CircuitBreakerModule(settings));
// plugin modules must be added here, before others or we can get crazy injection errors...
for (Module pluginModule : pluginsService.nodeModules()) {
modules.add(pluginModule);
}
modules.add(new PluginsModule(pluginsService));
modules.add(new SettingsModule(this.settings));
modules.add(new NodeModule(this));
modules.add(new NetworkModule());
modules.add(new ScriptModule(this.settings));
modules.add(new EnvironmentModule(environment));
modules.add(new NodeEnvironmentModule(nodeEnvironment));
modules.add(new ClusterNameModule(this.settings));
modules.add(new ThreadPoolModule(threadPool));
modules.add(new DiscoveryModule(this.settings));
modules.add(new ClusterModule(this.settings));
modules.add(new RestModule(this.settings));
modules.add(new TransportModule(settings));
if (settings.getAsBoolean(HTTP_ENABLED, true)) {
modules.add(new HttpServerModule(settings));
}
modules.add(new IndicesModule(settings));
modules.add(new SearchModule(settings));
modules.add(new ActionModule(false));
modules.add(new MonitorModule(settings));
modules.add(new GatewayModule(settings));
modules.add(new NodeClientModule());
modules.add(new ShapeModule());
modules.add(new PercolatorModule());
modules.add(new ResourceWatcherModule());
modules.add(new RepositoriesModule());
modules.add(new TribeModule());
pluginsService.processModules(modules);
injector = modules.createInjector();
client = injector.getInstance(Client.class);
threadPool.setNodeSettingsService(injector.getInstance(NodeSettingsService.class));
success = true;
} finally {
if (!success) {
nodeEnvironment.close();
ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS);
}
}
logger.info("initialized");
}
通过它的构造函数可以清楚的看到elasticsearch加载了那些模块
modules.add(new DiscoveryModule(this.settings));
说明elasticsearch加载了DiscoveryModule。
每个discovery module 包含了不同的多个Discovery模块,每个discovery模块都是先了自己的publishi方法,通过广播的形式将master node接受到的node change event时间告诉其他的监听器。
其中最重要的就是 ZenDiscovery,它负责在局域网内通过多播(multi-broadcast)或者单播的形式发现其他节点并将之纳入cluster中。
第一次写关于开源项目研究的笔记,不尽之处希望大家多多指正。
有想一起研讨的也多多给我留言。