elasticsearch 啓動過程源碼(二)

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中。這裏應該是考慮到擴展問題。至於壓縮的使用,我們目前先不深究,先搞清楚啓動幹了什麼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章