本篇为elasticsearch源码分析系列文章的第八篇,又到了咱们深扒ElasticSearch源码的时候了:)java
本篇开始将会详细解释Node实例化的过程,从Node实例化这个操做为源点,了解ElasticSearch的编码思想,因为Node内容众多,因此会分篇叙述。node
前不久的分析中说到了,Node是ElasticSearch启动的重中之重,一个Node表明在一个集群(cluster.name)中的一个节点。为了使用客户端对集群进行操做,客户端可使用Node中的client()来取得org.elasticsearch.client.Client的实例。正则表达式
任什么时候候,启动一个elasticsearch实例都是启动Node的一个实例,多个Node实例的集合叫作Cluster。apache
集群中的节点默认均可以使用HTTP和Transport两种方法通讯。transport的通讯可使用Java TransportClient,而HTTP就只能使用Rest Client了。app
集群中的Node都能相互发现,并转发请求到合适节点。并且每一个Node会有如下的一个或多个做用:elasticsearch
Node类首先构造了三个Setting属性,分别是:函数
属性名 | key值 | 做用 |
---|---|---|
WRITE_PORTS_FILE_SETTING | node.portsfile | 用于控制是否将文件写入到包含给定传输类型端口的日志目录中 |
NODE_DATA_SETTING | node.data | 使该node被选举为data节点 |
NODE_MASTER_SETTING | node.master | 使该node被选举为master节点 |
NODE_INGEST_SETTING | node.ingest | 使该node被选举为ingest节点 |
NODE_LOCAL_STORAGE_SETTING | local_storage | 控制节点是否须要持久化元数据到磁盘,这和data node没有必然联系,可是若是local_storage为false,node.data和node.master的值必须为false |
NODE_NAME_SETTING | node.name | 节点名称 |
NODE_ATTRIBUTES | node.attr. | 添加gateway,zone,rack_id等参数key |
BREAKER_TYPE_KEY | indices.breaker.type | 断路器类型,提供参数有hierarchy,none两种,主要是防止内存溢出后elasticsearch宕机 |
三个Node的构造参数:源码分析
最重要的构造方法是:ui
protected Node(final Environment environment, Collection<Class<? extends Plugin>> classpathPlugins)
复制代码
该构造方法所作的工做:编码
咱们的源码解析也会按照这个流程来开展。
在Node刚开始构造的时候,这个时候Node对象中尚未存在Setting实例的,有的配置只有在BootStrap方法中传过来的Environment实例,这个Envi的实例(environment)其实就是解析了启动环境中若干的配置路径(lib路径,module路径,logs路径),在对environment的setting化后(调用Environment的settings()方法,就是对初始的环境变量标准化为Settings类型的对象),以下图:
在构造完这个最初始版本的Settings后,代码视图取得配置中的node.name,为何会在Node刚开始初始化的时候就去查找node的name呢?在跟进源码后会知道,ElasticSearch这么作是为了给Logger的实例增长marker这个参数,相信对log4j熟悉的同窗会对这个参数很熟悉,merker是log4j中LayoutPattern的参数之一,做用是event元素中的标记元素,这种标记元素仅在日志消息中使用标记时出现,且具备继承性。以下图:
固然若是配置了node.name,且在log4j.properties中配置了属性appender.console.layout.pattern包含元素**%marker**,那么在控制台中会很容易看到形以下图中的日志打印,这就能很容易区分出日志的归属Node。
固然到这里咱们都还没给Node设置名称。
接下来给Node设置了client.type的值为node,这个也是写在代码里的配置。
private static final String CLIENT_TYPE = "node";
复制代码
接下来开始就开始构建NodeEnvironment实例了。
首先说明Environment和NodeEnvironment是没有任何继承关系的,只是在NodeEnvironment的实例化过程当中,Environment做为了构建所必需的参数。NodeEnvironment主要是针对单个节点的包含全部数据路径的构件对象,说白了这个类就是xxx,直接看NodeEnvironment构造函数。构造函数中经过累加possibleLockId的值来新增数据存储的路径,这个值是从0开始的,因此才会在ElasticSearch的数据存储页面生成以下图的文件夹:
接下来使用FSDirectory.open(dir, NativeFSLockFactory.INSTANCE)
获取存储索引的目录,FSDirectory是对文件系统目录的操做
经过locks[dirIndex] = luceneDir.obtainLock(NODE_LOCK_FILENAME)
;取得锁后生成一个内部类NodePath的实例,到这里锁就持久化到磁盘上了。
补充一句,这个地方涉及到了ElasticSearch的参数max_local_storage_nodes,这个配置限制了单节点上能够开启的ES存储实例的个数,若是咱们须要开多个实例,就要把这个配置写到配置文件中,并为这个配置赋值为2或者更高,这样的话ElasticSearch就会用for循环建立多个NodePath,而不仅是建立惟一的那个ID为0的实例。
在NodeEnvironment中加载或建立Node元数据
接下类是构造NodeMetaData节点元数据,这个元数据有个关键数据叫nodeId,构造出来后是形如D2_COg3LTUeQcrYjcj_fQQ这样的字符串。
程序执行到这个地方,其内部类NodePath的对象里已经保存了节点目录xxxx\data\nodes\0和节点索引目录xxxx\data\nodes\0\indices,以下图所示:
程序首先经过DirectoryStream<Path> paths = Files.newDirectoryStream(stateDir)
遍历data\nodes\0_state文件夹下的状态文件,再经过匹配正则表达式\Qnode-\E(\d+)(.st)?
,查找到状态文件node-xxx.st。
注意,若是有多个数据存储路径,那么状态文件夹下可能会有多个最新状态版本。这种状况下,只会取最高的版本。若是至少有一个状态文件使用了新的格式(format,也就是编码中的legacy==false),那么最新的状态文件确定是最新的的格式(format)。若是不是使用最新的状态文件,那编码中的pathAndStateIds值是空的,且会在日志中报加载状态文件失败的错误。
最后从node-xxx.st文件中读出ID,至此NodeMetaData对象的nodeId字段就被赋值了。而这个ID的前缀也被做为Logger的marker值被注入。
至此nodeEnvironment = new NodeEnvironment(tmpSettings, environment);
的工做就结束了,总而言之就是载入了状态参数到内存中。
下一篇会讲述pluginsService相关的内容,但愿你们持续关注哦^ _ ^。