Remove all datanode leader node usages (#19170)

* Remove all datanode leader node usages

* Added changelog

* Fixed rest client injection

* fix datanode isLeader in builder

* Remove leader selector in datanode proxy implementations
This commit is contained in:
Tomas Dvorak
2024-04-29 17:20:40 +02:00
committed by GitHub
parent fdac618be8
commit ba211bf2a6
16 changed files with 43 additions and 230 deletions

View File

@@ -19,7 +19,6 @@ package org.graylog.datanode.bindings;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
import org.graylog.datanode.bootstrap.preflight.DataNodeConfigurationPeriodical;
import org.graylog.datanode.periodicals.ClusterManagerDiscovery;
import org.graylog.datanode.periodicals.MetricsCollector;
import org.graylog.datanode.periodicals.NodePingPeriodical;
import org.graylog.datanode.periodicals.OpensearchNodeHeartbeat;
@@ -34,7 +33,6 @@ public class PeriodicalBindings extends AbstractModule {
periodicalBinder.addBinding().to(ClusterEventPeriodical.class);
periodicalBinder.addBinding().to(ClusterEventCleanupPeriodical.class);
periodicalBinder.addBinding().to(OpensearchNodeHeartbeat.class);
periodicalBinder.addBinding().to(ClusterManagerDiscovery.class);
// periodicalBinder.addBinding().to(UserSessionTerminationPeriodical.class);
periodicalBinder.addBinding().to(NodePingPeriodical.class);
periodicalBinder.addBinding().to(DataNodeConfigurationPeriodical.class);

View File

@@ -139,7 +139,6 @@ public class Server extends ServerBootstrap {
// always set leader to "false" on startup and let the NodePingPeriodical take care of it later
nodeService.registerServer(DataNodeDto.Builder.builder()
.setId(nodeId.getNodeId())
.setLeader(false)
.setTransportAddress(configuration.getHttpPublishUri().toString())
.setHostname(Tools.getLocalCanonicalHostname())
.setDataNodeStatus(DataNodeStatus.STARTING)

View File

@@ -19,6 +19,6 @@ package org.graylog.datanode.opensearch;
import org.graylog.datanode.opensearch.statemachine.OpensearchState;
import org.graylog.datanode.process.ProcessInformation;
public record OpensearchInfo(String nodeName, OpensearchState state, boolean isLeaderNode, String restBaseUrl,
public record OpensearchInfo(String nodeName, OpensearchState state, String restBaseUrl,
ProcessInformation process) {
}

View File

@@ -34,9 +34,6 @@ public interface OpensearchProcess extends ManagableProcess<OpensearchConfigurat
Optional<RestHighLevelClient> restClient();
Optional<OpenSearchClient> openSearchClient();
boolean isLeaderNode();
void setLeaderNode(boolean isManagerNode);
List<String> stdOutLogs();
List<String> stdErrLogs();

View File

@@ -70,7 +70,6 @@ class OpensearchProcessImpl implements OpensearchProcess, ProcessListener {
private final DatanodeConfiguration datanodeConfiguration;
private boolean isLeaderNode;
private OpensearchCommandLineProcess commandLineProcess;
private final Queue<String> stdout;
@@ -116,7 +115,7 @@ class OpensearchProcessImpl implements OpensearchProcess, ProcessListener {
}
public OpensearchInfo processInfo() {
return new OpensearchInfo(configuration.getDatanodeNodeName(), processState.getState(), isLeaderNode, getOpensearchBaseUrl().toString(), commandLineProcess != null ? commandLineProcess.processInfo() : ProcessInformation.empty());
return new OpensearchInfo(configuration.getDatanodeNodeName(), processState.getState(), getOpensearchBaseUrl().toString(), commandLineProcess != null ? commandLineProcess.processInfo() : ProcessInformation.empty());
}
@Override
@@ -156,15 +155,6 @@ class OpensearchProcessImpl implements OpensearchProcess, ProcessListener {
this.processState.getTracerAggregator().addTracer((StateMachineTracer) stateMachineTracer);
}
public void setLeaderNode(boolean isLeaderNode) {
this.isLeaderNode = isLeaderNode;
}
@Override
public boolean isLeaderNode() {
return isLeaderNode;
}
public boolean isInState(OpensearchState expectedState) {
return this.processState.getState().equals(expectedState);
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode.periodicals;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.graylog.datanode.Configuration;
import org.graylog.datanode.configuration.DatanodeConfiguration;
import org.graylog.datanode.opensearch.OpensearchProcess;
import org.graylog.datanode.opensearch.statemachine.OpensearchState;
import org.graylog.shaded.opensearch2.org.opensearch.client.Request;
import org.graylog.shaded.opensearch2.org.opensearch.client.Response;
import org.graylog.shaded.opensearch2.org.opensearch.client.RestHighLevelClient;
import org.graylog2.plugin.periodical.Periodical;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Optional;
@Singleton
public class ClusterManagerDiscovery extends Periodical {
private static final Logger LOG = LoggerFactory.getLogger(ClusterManagerDiscovery.class);
private final DatanodeConfiguration datanodeConfiguration;
private final OpensearchProcess managedOpenSearch;
private final ObjectMapper objectMapper;
private final Configuration configuration;
@Inject
public ClusterManagerDiscovery(DatanodeConfiguration datanodeConfiguration, OpensearchProcess managedOpenSearch, ObjectMapper objectMapper, Configuration configuration) {
this.datanodeConfiguration = datanodeConfiguration;
this.managedOpenSearch = managedOpenSearch;
this.objectMapper = objectMapper;
this.configuration = configuration;
}
@Override
// This method is "synchronized" because we are also calling it directly in AutomaticLeaderElectionService
public synchronized void doRun() {
if (managedOpenSearch.isInState(OpensearchState.AVAILABLE)) {
final Boolean isManagerNode = getClusterStateResponse(managedOpenSearch)
.map(r -> r.nodes().get(r.clusterManagerNode()))
.map(managerNode -> configuration.getDatanodeNodeName().equals(managerNode.name()))
.orElse(false);
managedOpenSearch.setLeaderNode(isManagerNode);
}
}
private Optional<ClusterStateResponse> getClusterStateResponse(OpensearchProcess process) {
return process.restClient().flatMap(this::requestClusterState);
}
private Optional<ClusterStateResponse> requestClusterState(RestHighLevelClient client) {
try {
final Response response = client.getLowLevelClient().performRequest(new Request("GET", "_cluster/state/"));
final ClusterStateResponse state = objectMapper.readValue(response.getEntity().getContent(), ClusterStateResponse.class);
return Optional.of(state);
} catch (IOException e) {
LOG.warn("Failed to obtain cluster state response", e);
return Optional.empty();
}
}
@Override
protected Logger getLogger() {
return LOG;
}
@Override
public boolean runsForever() {
return false;
}
@Override
public boolean stopOnGracefulShutdown() {
return false;
}
@Override
public boolean leaderOnly() {
return false;
}
@Override
public boolean startOnThisNode() {
return true;
}
@Override
public boolean isDaemon() {
return true;
}
@Override
public int getInitialDelaySeconds() {
return 0;
}
@Override
public int getPeriodSeconds() {
return 10;
}
}

View File

@@ -21,9 +21,9 @@ import com.google.common.collect.ImmutableMap;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import org.graylog.datanode.Configuration;
import org.graylog.datanode.opensearch.OpensearchProcess;
import org.graylog.datanode.metrics.ClusterStatMetricsCollector;
import org.graylog.datanode.metrics.NodeMetricsCollector;
import org.graylog.datanode.opensearch.OpensearchProcess;
import org.graylog.datanode.opensearch.statemachine.OpensearchState;
import org.graylog.shaded.opensearch2.org.joda.time.DateTime;
import org.graylog.shaded.opensearch2.org.joda.time.DateTimeZone;
@@ -31,7 +31,9 @@ import org.graylog.shaded.opensearch2.org.opensearch.action.index.IndexRequest;
import org.graylog.shaded.opensearch2.org.opensearch.action.index.IndexResponse;
import org.graylog.shaded.opensearch2.org.opensearch.action.search.SearchRequest;
import org.graylog.shaded.opensearch2.org.opensearch.action.search.SearchResponse;
import org.graylog.shaded.opensearch2.org.opensearch.client.Request;
import org.graylog.shaded.opensearch2.org.opensearch.client.RequestOptions;
import org.graylog.shaded.opensearch2.org.opensearch.client.Response;
import org.graylog.shaded.opensearch2.org.opensearch.client.RestHighLevelClient;
import org.graylog.shaded.opensearch2.org.opensearch.core.action.ActionListener;
import org.graylog.shaded.opensearch2.org.opensearch.index.query.QueryBuilders;
@@ -50,6 +52,7 @@ import java.lang.management.MemoryUsage;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
public class MetricsCollector extends Periodical {
@@ -59,7 +62,6 @@ public class MetricsCollector extends Periodical {
private NodeMetricsCollector nodeStatMetricsCollector;
private ClusterStatMetricsCollector clusterStatMetricsCollector;
private final ObjectMapper objectMapper;
private boolean isLeader;
@Inject
public MetricsCollector(OpensearchProcess process, Configuration configuration, ObjectMapper objectMapper) {
@@ -110,8 +112,6 @@ public class MetricsCollector extends Periodical {
process.restClient().ifPresent(client -> {
this.nodeStatMetricsCollector = new NodeMetricsCollector(client, objectMapper);
this.clusterStatMetricsCollector = new ClusterStatMetricsCollector(client, objectMapper);
this.isLeader = process.isLeaderNode();
final IndexRequest indexRequest = new IndexRequest(configuration.getMetricsStream());
Map<String, Object> metrics = new HashMap<String, Object>();
metrics.put(configuration.getMetricsTimestamp(), new DateTime(DateTimeZone.UTC));
@@ -122,17 +122,36 @@ public class MetricsCollector extends Periodical {
indexRequest.source(metrics);
indexDocument(client, indexRequest);
if (isLeader) {
if (isManagerNode(process)) {
metrics = new HashMap<>(clusterStatMetricsCollector.getClusterMetrics(getPreviousMetricsForCluster(client)));
metrics.put(configuration.getMetricsTimestamp(), new DateTime(DateTimeZone.UTC));
indexRequest.source(metrics);
indexDocument(client, indexRequest);
}
});
}
}
public boolean isManagerNode(OpensearchProcess process) {
return process.restClient()
.flatMap(this::requestClusterState)
.map(r -> r.nodes().get(r.clusterManagerNode()))
.map(managerNode -> configuration.getDatanodeNodeName().equals(managerNode.name()))
.orElse(false);
}
private Optional<ClusterStateResponse> requestClusterState(RestHighLevelClient client) {
try {
final Response response = client.getLowLevelClient().performRequest(new Request("GET", "_cluster/state/"));
final ClusterStateResponse state = objectMapper.readValue(response.getEntity().getContent(), ClusterStateResponse.class);
return Optional.of(state);
} catch (IOException e) {
LOG.warn("Failed to obtain cluster state response", e);
return Optional.empty();
}
}
private void addJvmMetrics(Map<String, Object> metrics) {
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
metrics.put("dn_heap_usage", calcUsage(memoryMXBean.getHeapMemoryUsage()));

View File

@@ -40,7 +40,6 @@ public class NodePingPeriodical extends Periodical {
private final Supplier<URI> opensearchBaseUri;
private final Supplier<String> opensearchClusterUri;
private final Supplier<String> datanodeRestApiUri;
private final Supplier<Boolean> isLeader;
private final Configuration configuration;
private final Supplier<OpensearchState> processState;
@@ -54,7 +53,6 @@ public class NodePingPeriodical extends Periodical {
managedOpenSearch::getOpensearchBaseUrl,
managedOpenSearch::getOpensearchClusterUrl,
managedOpenSearch::getDatanodeRestApiUrl,
managedOpenSearch::isLeaderNode,
() -> managedOpenSearch.processInfo().state()
);
}
@@ -66,7 +64,6 @@ public class NodePingPeriodical extends Periodical {
Supplier<URI> opensearchBaseUri,
Supplier<String> opensearchClusterUri,
Supplier<String> datanodeRestApiUri,
Supplier<Boolean> isLeader,
Supplier<OpensearchState> processState
) {
this.nodeService = nodeService;
@@ -74,7 +71,6 @@ public class NodePingPeriodical extends Periodical {
this.opensearchBaseUri = opensearchBaseUri;
this.opensearchClusterUri = opensearchClusterUri;
this.datanodeRestApiUri = datanodeRestApiUri;
this.isLeader = isLeader;
this.configuration = configuration;
this.processState = processState;
}
@@ -124,7 +120,6 @@ public class NodePingPeriodical extends Periodical {
public void doRun() {
final DataNodeDto dto = DataNodeDto.Builder.builder()
.setId(nodeId.getNodeId())
.setLeader(isLeader.get())
.setTransportAddress(opensearchBaseUri.get().toString())
.setClusterAddress(opensearchClusterUri.get())
.setDataNodeStatus(processState.get().getDataNodeStatus())
@@ -139,7 +134,6 @@ public class NodePingPeriodical extends Periodical {
private void registerServer() {
final boolean registrationSucceeded = nodeService.registerServer(DataNodeDto.Builder.builder()
.setId(nodeId.getNodeId())
.setLeader(isLeader.get())
.setTransportAddress(opensearchBaseUri.get().toString())
.setClusterAddress(opensearchClusterUri.get())
.setHostname(configuration.getHostname())