Remove `gateway.initial_meta` and always rely on min master nodes
During initial cluster forming, when a master is elected, it reaches out to all other masters nodes and ask the last cluster state they persisted. To make sure we select the right state, we must successfully read from a `min_master_nodes` nodes. The gateway currently have specific settings to override this behavior, but I don't think they are ever used. We can drop them and reach out to the discovery layer, the single source of truth for the min master nodes settings. Closes #16446
This commit is contained in:
parent
e69350f2ba
commit
924e880480
|
@ -93,4 +93,10 @@ public interface Discovery extends LifecycleComponent<Discovery> {
|
|||
*/
|
||||
DiscoveryStats stats();
|
||||
|
||||
|
||||
/***
|
||||
* @return the current value of minimum master nodes, or -1 for not set
|
||||
*/
|
||||
int getMinimumMasterNodes();
|
||||
|
||||
}
|
||||
|
|
|
@ -299,6 +299,11 @@ public class LocalDiscovery extends AbstractLifecycleComponent<Discovery> implem
|
|||
return new DiscoveryStats(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumMasterNodes() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private LocalDiscovery[] members() {
|
||||
ClusterGroup clusterGroup = clusterGroups.get(clusterName);
|
||||
if (clusterGroup == null) {
|
||||
|
|
|
@ -354,6 +354,11 @@ public class ZenDiscovery extends AbstractLifecycleComponent<Discovery> implemen
|
|||
return new DiscoveryStats(queueStats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumMasterNodes() {
|
||||
return electMaster.minimumMasterNodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if zen discovery is started and there is a currently a background thread active for (re)joining
|
||||
* the cluster used for testing.
|
||||
|
|
|
@ -34,9 +34,11 @@ import org.elasticsearch.cluster.metadata.MetaData;
|
|||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.discovery.Discovery;
|
||||
import org.elasticsearch.env.NodeEnvironment;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -51,23 +53,21 @@ public class Gateway extends AbstractComponent implements ClusterStateListener {
|
|||
|
||||
private final TransportNodesListGatewayMetaState listGatewayMetaState;
|
||||
|
||||
private final String initialMeta;
|
||||
private final ClusterName clusterName;
|
||||
|
||||
private final Supplier<Integer> minimumMasterNodesProvider;
|
||||
|
||||
@Inject
|
||||
public Gateway(Settings settings, ClusterService clusterService, NodeEnvironment nodeEnv, GatewayMetaState metaState,
|
||||
TransportNodesListGatewayMetaState listGatewayMetaState, ClusterName clusterName) {
|
||||
TransportNodesListGatewayMetaState listGatewayMetaState, ClusterName clusterName, Discovery discovery) {
|
||||
super(settings);
|
||||
this.clusterService = clusterService;
|
||||
this.nodeEnv = nodeEnv;
|
||||
this.metaState = metaState;
|
||||
this.listGatewayMetaState = listGatewayMetaState;
|
||||
this.clusterName = clusterName;
|
||||
|
||||
this.minimumMasterNodesProvider = discovery::getMinimumMasterNodes;
|
||||
clusterService.addLast(this);
|
||||
|
||||
// we define what is our minimum "master" nodes, use that to allow for recovery
|
||||
this.initialMeta = settings.get("gateway.initial_meta", settings.get("gateway.local.initial_meta", settings.get("discovery.zen.minimum_master_nodes", "1")));
|
||||
}
|
||||
|
||||
public void performStateRecovery(final GatewayStateRecoveredListener listener) throws GatewayException {
|
||||
|
@ -76,7 +76,7 @@ public class Gateway extends AbstractComponent implements ClusterStateListener {
|
|||
TransportNodesListGatewayMetaState.NodesGatewayMetaState nodesState = listGatewayMetaState.list(nodesIds.toArray(String.class), null).actionGet();
|
||||
|
||||
|
||||
int requiredAllocation = calcRequiredAllocations(this.initialMeta, nodesIds.size());
|
||||
int requiredAllocation = Math.max(1, minimumMasterNodesProvider.get());
|
||||
|
||||
|
||||
if (nodesState.failures().length > 0) {
|
||||
|
@ -143,35 +143,6 @@ public class Gateway extends AbstractComponent implements ClusterStateListener {
|
|||
builder.metaData(metaDataBuilder);
|
||||
listener.onSuccess(builder.build());
|
||||
}
|
||||
|
||||
protected int calcRequiredAllocations(final String setting, final int nodeCount) {
|
||||
int requiredAllocation = 1;
|
||||
try {
|
||||
if ("quorum".equals(setting)) {
|
||||
if (nodeCount > 2) {
|
||||
requiredAllocation = (nodeCount / 2) + 1;
|
||||
}
|
||||
} else if ("quorum-1".equals(setting) || "half".equals(setting)) {
|
||||
if (nodeCount > 2) {
|
||||
requiredAllocation = ((1 + nodeCount) / 2);
|
||||
}
|
||||
} else if ("one".equals(setting)) {
|
||||
requiredAllocation = 1;
|
||||
} else if ("full".equals(setting) || "all".equals(setting)) {
|
||||
requiredAllocation = nodeCount;
|
||||
} else if ("full-1".equals(setting) || "all-1".equals(setting)) {
|
||||
if (nodeCount > 1) {
|
||||
requiredAllocation = nodeCount - 1;
|
||||
}
|
||||
} else {
|
||||
requiredAllocation = Integer.parseInt(setting);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("failed to derived initial_meta from value {}", setting);
|
||||
}
|
||||
return requiredAllocation;
|
||||
}
|
||||
|
||||
public void reset() throws Exception {
|
||||
try {
|
||||
Path[] dataPaths = nodeEnv.nodeDataPaths();
|
||||
|
|
|
@ -122,6 +122,11 @@ public class DiscoveryModuleTests extends ModuleTestCase {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumMasterNodes() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle.State lifecycleState() {
|
||||
return null;
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.elasticsearch.cluster.ClusterService;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.ModuleTestCase;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.discovery.Discovery;
|
||||
import org.elasticsearch.env.NodeEnvironment;
|
||||
|
||||
public class GatewayModuleTests extends ModuleTestCase {
|
||||
|
@ -41,8 +42,9 @@ public class GatewayModuleTests extends ModuleTestCase {
|
|||
public static class MockGateway extends Gateway {
|
||||
|
||||
@Inject
|
||||
public MockGateway(Settings settings, ClusterService clusterService, NodeEnvironment nodeEnv, GatewayMetaState metaState, TransportNodesListGatewayMetaState listGatewayMetaState, ClusterName clusterName) {
|
||||
super(settings, clusterService, nodeEnv, metaState, listGatewayMetaState, clusterName);
|
||||
public MockGateway(Settings settings, ClusterService clusterService, NodeEnvironment nodeEnv, GatewayMetaState metaState,
|
||||
TransportNodesListGatewayMetaState listGatewayMetaState, ClusterName clusterName, Discovery discovery) {
|
||||
super(settings, clusterService, nodeEnv, metaState, listGatewayMetaState, clusterName, discovery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.gateway;
|
||||
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.cluster.TestClusterService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
|
||||
public class GatewayTests extends ESTestCase {
|
||||
|
||||
public void testCalcRequiredAllocations() {
|
||||
MockGateway gateway = new MockGateway(Settings.EMPTY, new TestClusterService());
|
||||
int nodeCount = randomIntBetween(1, 6);
|
||||
Map<String, Integer> expectedResult = new HashMap<>();
|
||||
expectedResult.put("quorum", nodeCount > 2 ? nodeCount / 2 + 1 : 1);
|
||||
expectedResult.put("quorum-1", nodeCount > 2 ? (nodeCount + 1) / 2 : 1);
|
||||
expectedResult.put("half", expectedResult.get("quorum-1"));
|
||||
expectedResult.put("one", 1);
|
||||
expectedResult.put("full", nodeCount);
|
||||
expectedResult.put("all", nodeCount);
|
||||
expectedResult.put("full-1", Math.max(1, nodeCount - 1));
|
||||
expectedResult.put("all-1", Math.max(1, nodeCount - 1));
|
||||
int i = randomIntBetween(1, 20);
|
||||
expectedResult.put("" + i, i);
|
||||
expectedResult.put(randomUnicodeOfCodepointLength(10), 1);
|
||||
for (String setting : expectedResult.keySet()) {
|
||||
assertThat("unexpected result for setting [" + setting + "]", gateway.calcRequiredAllocations(setting, nodeCount), equalTo(expectedResult.get(setting).intValue()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MockGateway extends Gateway {
|
||||
|
||||
MockGateway(Settings settings, ClusterService clusterService) {
|
||||
super(settings, clusterService, null, null, null, ClusterName.DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calcRequiredAllocations(String setting, int nodeCount) {
|
||||
return super.calcRequiredAllocations(setting, nodeCount);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue