本篇爲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相關的內容,但願你們持續關注哦^ _ ^。