【Elasticsearch 5.6.12 原始碼】——【2】啟動過程分析(上)
版權宣告:本文為博主原創,轉載請註明出處!
簡介
本文主要解決以下問題:
1、啟動ES的入口類及入口方法是哪個?
2、分析梳理ES服務啟動的主要流程?
入口類
ES的入口類為org.elasticsearch.bootstrap.Elasticsearch
,啟動方法為:
public static void main(final String[] args) throws Exception
該類通過繼承EnvironmentAwareCommand類增加了CLI的支援,類圖:
啟動流程
Step 1、給JVM安裝(臨時的)安全管理器,並註冊錯誤日誌監聽器。
ES在程式啟動的第一步先給JVM安裝了一個安全管理器,並授予了程式所有的許可權(臨時的,後續會更換新的安全管理器),以方便以後的操作。接下來會註冊一個錯誤日誌的監聽器,來監聽是否有錯誤發生,隨後使用配置檔案配置日誌元件是會檢查監聽器是否檢測到錯誤,如果有將通過拋異常的方式中止ES的啟動過程。執行該動作的方法:
// org.elasticsearch.bootstrap.Elasticsearch
public static void main(final String[] args) throws Exception
Step 2、建立一個Elasticsearch類的例項(一個CLI的Command例項),並執行例項的main方法。
Elasticsearch類直接繼承了EnvironmentAwareCommand,可以認為這一步建立了一個CLI的command物件。在該類的構造方法以及父類中定義了該
command
物件可以接受的cli的引數。執行該動作的方法:
// org.elasticsearch.bootstrap.Elasticsearch public static void main(final String[] args) throws Exception
在
bin
目錄下執行Elasticsearch -h
命令,可以檢視該例項支援的所有命令列引數:
Step 3、新增JVM關閉的構造,使用預設配置配置日誌元件。
為JVM添加了一個shutdown的鉤子函式,在鉤子函式中呼叫了close()方法。使用系統屬性
es.logger.level
的值來配置日誌元件,如果沒有該配置則使用預設的INFO
級別來配置logger.level
。執行該動作的方法:
// org.elasticsearch.cli.Command public final int main(String[] args, Terminal terminal) throws Exception
Step 4、解析help
、silent
、verbose
或normal
的引數配置,並輸出或設定到Terminal
上。
首先檢查控制檯是否傳入了
-h
或--help
引數,如果有的話列印幫助資訊,並結束ES的啟動過程。否則,依次檢查-s
、-v
等引數,並根據相應的引數配置terminal
的資訊輸出方式。執行該動作的方法:
// org.elasticsearch.cli.Command
void mainWithoutErrorHandling(String[] args, Terminal terminal) throws Exception
Step 5、解析通過控制檯傳入的ES的配置引數,並根據配置引數建立Environment物件。
首先,解析通過控制檯
-E
引數傳入的ES配置。其次,通過System Property
補齊某些確實的配置。這兩個過程都會對配置的key進行查重。解析配置的程式碼:
// org.elasticsearch.cli.EnvironmentAwareCommand
protected void execute(Terminal terminal, OptionSet options) throws Exception {
final Map<String, String> settings = new HashMap<>();
for (final KeyValuePair kvp : settingOption.values(options)) {
if (kvp.value.isEmpty()) {
throw new UserException(ExitCodes.USAGE, "setting [" + kvp.key + "] must not be empty");
}
if (settings.containsKey(kvp.key)) {
final String message = String.format(
Locale.ROOT,
"setting [%s] already set, saw [%s] and [%s]",
kvp.key,
settings.get(kvp.key),
kvp.value);
throw new UserException(ExitCodes.USAGE, message);
}
settings.put(kvp.key, kvp.value);
}
putSystemPropertyIfSettingIsMissing(settings, "default.path.conf", "es.default.path.conf");
putSystemPropertyIfSettingIsMissing(settings, "default.path.data", "es.default.path.data");
putSystemPropertyIfSettingIsMissing(settings, "default.path.logs", "es.default.path.logs");
putSystemPropertyIfSettingIsMissing(settings, "path.conf", "es.path.conf");
putSystemPropertyIfSettingIsMissing(settings, "path.data", "es.path.data");
putSystemPropertyIfSettingIsMissing(settings, "path.home", "es.path.home");
putSystemPropertyIfSettingIsMissing(settings, "path.logs", "es.path.logs");
execute(terminal, options, createEnv(terminal, settings));
}
接下來,根據解析到的配置項來建立Environment物件。
// org.elasticsearch.cli.EnvironmentAwareCommand
protected Environment createEnv(Terminal terminal, Map<String, String> settings) {
return InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings);
}
最終,通過InternalSettingsPreparer物件的prepareEnironment方法來建立Enironment物件。
// org.elasticsearch.node.InternalSettingsPreparer
public static Environment prepareEnvironment(Settings input, Terminal terminal, Map<String, String> properties)
該方法會合並控制檯傳入的配置項、部分通過系統環境變數設定的配置項及
elasticsearch.yml
設定的配置項。最終建立一個Environment物件,該物件中儲存了ES程式的配置目錄、資料目錄、外掛目錄及日誌目錄的地址。
Step 6、解析控制檯傳入的-v
、-d
、-p
及-q
等引數,並依據相應的引數初始化Bootstrap
。
首先,檢查是否傳入了
-v
引數,如果有該引數則列印ES的版本資訊並退出。接下來解析-d
、-p
及-q
引數,並依據這些引數呼叫Bootstrap.init
。執行該動作的方法:
// org.elasticsearch.bootstrap.Elasticsearch
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException
void init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv)
Step 7、通過呼叫BootstrapInfo.init()
方法的方式來初始化BootstrapInfo
物件。
通過這個物件可以獲取
JNA
是否可用、系統Memory Lock
是否可用等一些系統資訊。執行該動作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 8、建立一個Bootstrap
例項,載入Secure Settings
,並結合原有的配置重新建立Environment
物件。
在
Bootstrap
例項中首先啟動了一個keep alive
執行緒。結合SecureSettings
重新建立Environment
物件。依據env
中的配置檔案配置日誌元件,這時會檢查是否有錯誤日誌產生。接下來輸出一些配置相關的日誌,並按需建立pidFile
。執行該動作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 9、檢查Lucene
的版本,設定 預設的未捕獲異常的處理器 ,並開始配置新建的Bootstrap
例項。
首先,根據是否守護經常執行的方式按需關閉
SysOut
。接下來檢查Lucene
庫的版本是否匹配。最後,設定DefaultUncaughtExceptionHandler
。執行該動作的方法:
// org.elasticsearch.bootstrap.Bootstrap
static void init(final boolean foreground, final Path pidFile,
final boolean quiet, final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException
Step 10、設定NativePluginControllers
,初始化native
資源,初始化資源“探針”,checkJarHell
,再次設定系統安全管理器並新建Node
物件。
在這些過程中間還會檢查老配置項
bootstrap.seccomp
和新配置項bootstrap.system_call_filter
都配置了的情況下是否產生了衝突。執行該動作的方法:
// org.elasticsearch.bootstrap.Bootstrap
private void setup(boolean addShutdownHook, Environment environment) throws BootstrapException
Step 11、關閉SecureSettings
的儲存檔案,並呼叫Bootstrap
物件的start
方法,按需closeSysError
。
這是啟動流程的最後一步。