elasticsearch 啓動過程源碼(二)
主要涉及nodebuilder,plugin初始化,node settings更新
注
es 版本1.0
上次我們講到了Bootstrap中的initialSettings,初始化配置文件,併產生了environment,後邊有什麼關鍵地方呢?在Bootstrap中的main方法有如下代碼
bootstrap.setup(true, tuple);
tuple是什麼呢?是initialSettings方法的返回值,v1是settings,v2是environment。
private void setup(boolean addShutdownHook, Tuple<Settings, Environment> tuple) throws Exception {
if (tuple.v1().getAsBoolean("bootstrap.mlockall", false)) {
Natives.tryMlockall();
}
tuple = setupJmx(tuple);
NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(tuple.v1()).loadConfigSettings(false);
node = nodeBuilder.build();
if (addShutdownHook) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
node.close();
}
});
}
}
先獲取bootstrap.mlockal的配置,用來進行mlockall操作,實際上此參數用來縮影物理內存,防止進行swap,在進行es性能優化的時候需要經常將此選項設置爲true來提高性能。Natives.tryMlockall()方法使用jna,來調用c語言的方法,不多說了,有興趣可以自己瞭解下jna。setupJmx方法沒有進行如何操作,下邊是關鍵的 nodeBuilder。NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(tuple.v1()).loadConfigSettings(false);調用nodeBuilder()方法new對象,後邊是設置對象的一些屬性。我們來看bulid()方法。
public Node build() {
return new InternalNode(settings.build(), loadConfigSettings);
}
new了一個InternalNode對象。以下是此對象的構造方法。
InternalNode.java
public InternalNode(Settings pSettings, boolean loadConfigSettings) throws ElasticsearchException {
// pSettings 配置文件 和loadConfigSettings=false 調用prepareSettings 新得到一個 tuple
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(pSettings, loadConfigSettings);
//根據settings 添加tribe node 配置
tuple = new Tuple<Settings, Environment>(TribeService.processSettings(tuple.v1()), tuple.v2());
Version version = Version.CURRENT;
ESLogger logger = Loggers.getLogger(Node.class, tuple.v1().get("name"));
logger.info("version[{}], pid[{}], build[{}/{}]", version, JvmInfo.jvmInfo().pid(), Build.CURRENT.hashShort(), Build.CURRENT.timestamp());
logger.info("initializing ...");
if (logger.isDebugEnabled()) {
Environment env = tuple.v2();
logger.debug("using home [{}], config [{}], data [{}], logs [{}], work [{}], plugins [{}]",
env.homeFile(), env.configFile(), Arrays.toString(env.dataFiles()), env.logsFile(),
env.workFile(), env.pluginsFile());
}
this.pluginsService = new PluginsService(tuple.v1(), tuple.v2()); //new pluginsService setting 中plugin.types
this.settings = pluginsService.updatedSettings(); //更新settings 來源於plugin中的additionalSettings
CompressorFactory.configure(settings);
//後邊若干代碼
}
TribeService.processSettings(tuple.v1())是什麼了,查了下資料,tribe node可以接收每個集羣的狀態,然後合併成一個全局集羣的狀態,它可以讀寫所有節點上的數據, 設置 tribe node後,每個節點是一個 tribe 客戶端,這裏就是根據settings中關於tribe的配置,來更新settings。至於更新的邏輯,肯定跟後邊不同節點初始化有關係,後邊我們涉及到就會清楚。代碼如下
TribeService.java
/*
若是settings含有tribe.name屬性,則將其他 tribe.*的配置移除
否則
獲取 前綴是 tribe 的屬性,若是null直接返回
否則
則這個節點是tribe節點,往setting中添加tribe node相關配置
*/
public static Settings processSettings(Settings settings) {
if (settings.get(TRIBE_NAME) != null) {
// if its a node client started by this service as tribe, remove any tribe group setting
// to avoid recursive configuration
ImmutableSettings.Builder sb = ImmutableSettings.builder().put(settings);
for (String s : settings.getAsMap().keySet()) {
if (s.startsWith("tribe.") && !s.equals(TRIBE_NAME)) {
sb.remove(s);
}
}
return sb.build();
}
Map<String, Settings> nodesSettings = settings.getGroups("tribe", true);
if (nodesSettings.isEmpty()) {
return settings;
}
// its a tribe configured node..., force settings
ImmutableSettings.Builder sb = ImmutableSettings.builder().put(settings);
sb.put("node.client", true); // this node should just act as a node client
sb.put("discovery.type", "local"); // a tribe node should not use zen discovery
sb.put("discovery.initial_state_timeout", 0); // nothing is going to be discovered, since no master will be elected
if (sb.get("cluster.name") == null) {
sb.put("cluster.name", "tribe_" + Strings.randomBase64UUID()); // make sure it won't join other tribe nodes in the same JVM
}
sb.put("gateway.type", "none"); // we shouldn't store anything locally...
sb.put(TransportMasterNodeReadOperationAction.FORCE_LOCAL_SETTING, true);
return sb.build();
}
再來看plugin相關代碼this.pluginsService = new PluginsService(tuple.v1(), tuple.v2());這行代碼new了一個PluginsService,在這個構造函數中的重要功能有
1.使用反射將settings 中plugin.types的配置的className 生成plugin對象和pluginInfo對象
2.將environment中 plugin目錄 添加到ClassLoader的資源列表中
3.將資源文件中es-plugin.properties配置的plugin使用反射,生成plugin對象和pluginInfo對象
4.check settings中配置的plugin.mandatory 是否都存在。
5.初始化onModuleReferences屬性,此map記錄了那些含有onModule(Module module,...)方法的plugin
6.其他屬性的初始化refreshInterval,componentSettings,environment,settings
相關代碼比較長,這裏直接上github的鏈接
然後進行this.settings = pluginsService.updatedSettings();
public Settings updatedSettings() {
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder()
.put(this.settings);
for (Tuple<PluginInfo, Plugin> plugin : plugins) {
builder.put(plugin.v2().additionalSettings());
}
return builder.build();
}
實際上就是更新來源於plugin中的additionalSettings到settings中。
再來看看CompressorFactory.configure(settings);
public class CompressorFactory {
private static final LZFCompressor LZF = new LZFCompressor(); //初始化lzf壓縮
private static final Compressor[] compressors;
private static final ImmutableMap<String, Compressor> compressorsByType;
private static Compressor defaultCompressor;
static {
List<Compressor> compressorsX = Lists.newArrayList();
compressorsX.add(LZF);
compressors = compressorsX.toArray(new Compressor[compressorsX.size()]);
MapBuilder<String, Compressor> compressorsByTypeX = MapBuilder.newMapBuilder();
for (Compressor compressor : compressors) {
compressorsByTypeX.put(compressor.type(), compressor); //每種類型的壓縮 只有一個?
}
compressorsByType = compressorsByTypeX.immutableMap();
defaultCompressor = LZF;
}
public static synchronized void configure(Settings settings) {
for (Compressor compressor : compressors) {
compressor.configure(settings); // 配置文件 載入到 compressor中
}
String defaultType = settings.get("compress.default.type", "lzf").toLowerCase(Locale.ENGLISH);
boolean found = false;
for (Compressor compressor : compressors) {
if (defaultType.equalsIgnoreCase(compressor.type())) {
defaultCompressor = compressor;
found = true;
break;
}
}
if (!found) {
Loggers.getLogger(CompressorFactory.class).warn("failed to find default type [{}]", defaultType);
}
}
}
先看靜態代碼塊和靜態變量,初始化了一個LZFCompressor,然後添加到compressorsX中後邊又一系列轉化操作,但是compressorsX只有LZF,應該是1.0的時候只支持lzf壓縮。configure中處理配置文件中配置compress.default.type值並加settings傳入到compressor中,目前來看也就是lzf中。這裏應該是考慮到擴展問題。至於壓縮的使用,我們目前先不深究,先搞清楚啓動幹了什麼。