Основной процесс выбора Elasticsearch

Elasticsearch

Главный узел периодически отправляет эхо-запросы другим узлам в кластере, чтобы проверить, активен ли узел. обработать. Другие узлы также периодически проверяют, активен ли мастер.Если мастер не может быть восстановлен, узел повторно выполнит процесс выбора мастера.

Обнаружение узла и выбор мастера в кластере зависят от интерфейса обнаружения.Встроенная реализация ESZen Discovery

Основной избирательный алгоритм Elasticsearch — Bully

Количество узлов в кластере Elasticsearch ограничено, один узел может обрабатывать соединения со всеми другими узлами, а узлы не будут часто присоединяться и покидать кластер, поэтому Zen Discovery использует относительно простой алгоритм Bully.

В кластере есть мастер, который использует алгоритм Bully для хранения информации о состоянии всего кластера и регулярно передает информацию о версии состояния кластера другим узлам в кластере.Если алгоритм Bully используется напрямую, возникают следующие проблемы. будут обнаружены, поэтому Elasticsearch сделал специализацию обработки

Проблема 1: приостановленная анимация главного узла

Мастер может находиться в нестабильном состоянии из-за большой нагрузки и может не отвечать на запросы от некоторых узлов, но может вернуться в нормальное состояние за короткое время.Во избежание частых выборов ЭС использует метод отсрочки выборов пока мастер не выйдет из строя. Когда узел не получает ответа от мастера, он сначала запрашивает у других узлов список активных мастеров, а затем инициирует выборы после подтверждения того, что мастер умер.

Проблема 2: Разделенный мозг

Рассмотрим следующую ситуацию: исходный кластер состоит из A, B, C, D, E, а главный узел — это A. Когда соединение между двумя коммутаторами прерывается, A, B больше не могут взаимодействовать с C, D и E, образуя два сетевых раздела. В кластере, состоящем из A и B, ведущим по-прежнему является A, в то время как C, D и E выберут нового мастера.Когда клиент обращается к A, B или старшим C, D и E, данные несогласованны.

img

img

Elasticsearch принимает настройку «более половины голосов кворума».В процессе выборов, когда количество голосов узлов достигаетdiscovery.zen.minimum_master_nodesможет стать мастером только тогда, когда значение , которое обычно устанавливается равным(具有master资格节点数 / 2)+1.

в приведенном выше примереdiscovery.zen.minimum_master_nodesУстановите на 3. Когда соединение между двумя коммутаторами прерывается, A больше не может обмениваться данными с C, D и E. В сетевом разделе, состоящем из C, D и E, нет активного мастера, поэтому инициируются выборы. В кластере A остались только A и B, а minimum_master_nodes не хватает, поэтому они отказываются от статуса master. C, D и E голосуют до тех пор, пока не будет достигнут консенсус по выбору мастера для формирования нового кластера, где число узлов равно 3, что соответствует минимальному_мастер_узлу, а A и B больше не обрабатывают запросы от клиентов.

основной избирательный процесс

пройти черезZenDiscovery::findMasterОпределяем временного мастера:

private DiscoveryNode findMaster() {
    // 1. PING 所有节点,获取各节点保存的集群信息
    List<ZenPing.PingResponse> fullPingResponses = pingAndWait(pingTimeout).toList();
    
    // 2. 由于上面是获取的其他节点的信息,这里需要将本节点加上
    final DiscoveryNode localNode = transportService.getLocalNode();    
    fullPingResponses.add(new ZenPing.PingResponse(localNode, null, this.clusterState()));    
    // 3. 若设置了 master_election_ignore_non_masters 则去掉没有 master 资格(node.master: false)的节点
    final List<ZenPing.PingResponse> pingResponses = filterPingResponses(fullPingResponses, masterElectionIgnoreNonMasters, logger);
    
    // 4. 将各节点认为的 master 加入 activeMasters 列表
    List<DiscoveryNode> activeMasters = new ArrayList<>();    
    for (ZenPing.PingResponse pingResponse : pingResponses) {
        // 避免未经其他节点检查就将本节点选为 master
        if (pingResponse.master() != null && !localNode.equals(pingResponse.master())) {           
            activeMasters.add(pingResponse.master());        
        }    
    }    
    // 5. 将 PING 到的具有 master 资格的节点加入 masterCandidates 列表作为候选节点
    List<ElectMasterService.MasterCandidate> masterCandidates = new ArrayList<>();    
    for (ZenPing.PingResponse pingResponse : pingResponses) {        
        if (pingResponse.node().isMasterNode()) {            
            masterCandidates.add(new ElectMasterService.MasterCandidate(pingResponse.node(), pingResponse.getClusterStateVersion()));        
        }    
    }
    
    if (activeMasters.isEmpty()) {
        // 6. 没有活跃的 master
        if (electMaster.hasEnoughCandidates(masterCandidates)) {
            // 7. 拥有足够的候选节点,则进行选举
            final ElectMasterService.MasterCandidate winner = electMaster.electMaster(masterCandidates);                   
            return winner.getNode();        
        } else {
            // 8. 无法选举,无法得到 master,返回 null
            return null;        
        }    
    } else {
        assert !activeMasters.contains(localNode) : "local node should never be elected as master when other nodes indicate an active master";        
        // 9. 有活跃的 master,从 activeMasters 中选择
        return electMaster.tieBreakActiveMasters(activeMasters);    
    }
}
  1. Используется, когда нет активного ведущего, описанный выше шаг 7 выполняет выбор ведущего путемMasterCandidate::compareСравните узлы-кандидаты

    // ElectMasterService.MasterCandidate::compare
    public static int compare(MasterCandidate c1, MasterCandidate c2) {
        // 优先选择集群状态版本最新的节点
        int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
        if (ret == 0) {
            ret = compareNodes(c1.getNode(), c2.getNode());
        }
        return ret;
    }
    
    // ElectMasterService::compareNodes
    private static int compareNodes(DiscoveryNode o1, DiscoveryNode o2) {
        // 集群状态版本相同时优先选择具有 master 资格的节点
        if (o1.isMasterNode() && !o2.isMasterNode()) {
            return -1;
        }
        if (!o1.isMasterNode() && o2.isMasterNode()) {
            return 1;
        }
        // 以上条件都相同时选择 ID 较小的节点
        return o1.getId().compareTo(o2.getId());
    }
    
  2. Шаг 9 выше проходит, когда есть активный мастерElectMasterService::tieBreakAcitveMastersиспользоватьElectMasterService::compareNodesПравила выбираются из activeMasters

Ожидает ли узел или голосует в соответствии с выбранным временным мастером

if (transportService.getLocalNode().equals(masterNode)) {
    // 选出的临时 master 是本节点,则等待被选举为真正的 master
    final int requiredJoins = Math.max(0, electMaster.minimumMasterNodes() - 1);
    nodeJoinController.waitToBeElectedAsMaster(requiredJoins, masterElectionWaitForJoinsTimeout,
             new NodeJoinController.ElectionCallback() {
                 @Override
                 public void onElectedAsMaster(ClusterState state) {
                     // 成功被选举为 master
                     synchronized (stateMutex) {
                         joinThreadControl.markThreadAsDone(currentThread);
                     }
                 }

                 @Override
                 public void onFailure(Throwable t) {
                     // 等待超时,重新开始选举流程
                     synchronized (stateMutex) {
                         joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
                     }
                 }
             }
    );
} else {
    // 选出的临时 master 不是本节点,不再接收其他节点的 join 请求
    nodeJoinController.stopElectionContext(masterNode + " elected");

    // 向临时节点发送 join 请求(投票),被选举的临时 master 在确认成为 master 并发布新的集群状态后才会返回
    final boolean success = joinElectedMaster(masterNode);

    // 成功加入之前选择的临时 master 节点,则结束线程,否则重新选举
    synchronized (stateMutex) {
        if (success) {
             DiscoveryNode currentMasterNode = this.clusterState().getNodes().getMasterNode();
             if (currentMasterNode == null) {
                 joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
             } else if (currentMasterNode.equals(masterNode) == false) {
joinThreadControl.stopRunningThreadAndRejoin("master_switched_while_finalizing_join");
             }
             joinThreadControl.markThreadAsDone(currentThread);
        } else {
            joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
        }
    }
}

Выборы завершены

NodeJoinController::checkPendingJoinsAndElectIfNeededСделайте узел мастером, когда у него будет достаточно голосов, и опубликуйте новое состояние кластера.

private synchronized void checkPendingJoinsAndElectIfNeeded() {
    // 计算节点得票数
    final int pendingMasterJoins = electionContext.getPendingMasterJoinsCount();
    if (electionContext.isEnoughPendingJoins(pendingMasterJoins) == false) {
        ...
    } else {
        // 得票数足够,成为 master
        electionContext.closeAndBecomeMaster();
    }
}

public synchronized int getPendingMasterJoinsCount() {
    int pendingMasterJoins = 0;
    // 统计节点得票数,只计算拥有 master 资格节点的投票
    for (DiscoveryNode node : joinRequestAccumulator.keySet()) {
        if (node.isMasterNode()) {
            pendingMasterJoins++;
        }
    }
    return pendingMasterJoins;
}