Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster GET _cluster/settings API #86405

Merged

Conversation

grcevski
Copy link
Contributor

@grcevski grcevski commented May 3, 2022

The existing API to retrieve the cluster settings relies on
pulling in the full cluster state, which can be very expensive.

This change adds a dedicated cluster settings API, avoiding
serializing the full cluster state.

Closes #82342

Nikola Grcevski added 2 commits May 3, 2022 14:57
The existing API to retrieve the cluster settings relies on
pulling in the full cluster state, which can be very expensive.

This change adds a dedicated cluster settings API, avoiding
serializing the full cluster state.

Closes elastic#82342
@grcevski grcevski added >enhancement :Core/Infra/Core Core issues without another label Team:Core/Infra Meta label for core/infra team v8.3.0 labels May 3, 2022
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (Team:Core/Infra)

@elasticsearchmachine
Copy link
Collaborator

Hi @grcevski, I've created a changelog YAML for you.

}

public Settings settings() {
return Settings.builder().put(persistentSettings).put(transientSettings).build();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the right way to get the combined settings, it didn't make sense to double serialize across the transport protocol.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks right:

Settings.builder().put(persistentSettings).put(transientSettings).build(),

However I think it would be fine (preferable even) to send the combined settings separately from the transient and persistent ones, rather than duplicating this logic and risking getting it wrong.

Nikola Grcevski added 3 commits May 3, 2022 19:07
Copy link
Contributor

@DaveCTurner DaveCTurner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I left some small comments.

In terms of tests, yes this seems mostly pretty well covered. I think we should have some tests that verify that we haven't mixed up the persistent and transient settings anywhere along the way, and that the new transport action applies settings filters correctly. Also I think we should have an AbstractWireSerializingTestCase<ClusterGetSettingsAction.Response> (including a mutateInstance implementation) to ensure it round-trips properly.

}

public Settings settings() {
return Settings.builder().put(persistentSettings).put(transientSettings).build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks right:

Settings.builder().put(persistentSettings).put(transientSettings).build(),

However I think it would be fine (preferable even) to send the combined settings separately from the transient and persistent ones, rather than duplicating this logic and risking getting it wrong.

ActionListener<ClusterGetSettingsAction.Response> listener
) throws Exception {
Metadata metadata = state.metadata();
listener.onResponse(new ClusterGetSettingsAction.Response(metadata.persistentSettings(), metadata.transientSettings()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should apply the node's SettingsFilter here. That's sort of a change in behaviour since we don't filter the settings in the cluster state today, but then again this is a security thing and in most of the other transport actions that send settings around we do filter them.

public class ClusterGetSettingsAction extends ActionType<ClusterGetSettingsAction.Response> {

public static final ClusterGetSettingsAction INSTANCE = new ClusterGetSettingsAction();
public static final String NAME = "cluster:admin/settings/get";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be under cluster:monitor/* (maybe cluster:monitor/settings?) so that it's still permitted by clients that only have the monitor privilege.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, this way I can undo some of the changes I needed to do in xpack.

/**
* Response for cluster settings
*/
public static class Response extends ActionResponse implements ToXContentObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be implements ToXContentObject? I think we don't expose it as XContent directly, it's always converted to a RestClusterGetSettingsResponse first.

/**
* Cluster get settings request builder
*/
public static class RequestBuilder extends MasterNodeReadOperationRequestBuilder<Request, Response, RequestBuilder> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, do we really need all this client-facing machinery? AFAIK this pattern was good for the transport client, but we have no transport client any more so I think we can just call the action directly in the one place it's currently used.

* @param request The cluster settings request
* @return The result future
*/
ActionFuture<ClusterGetSettingsAction.Response> clusterSettings(ClusterGetSettingsAction.Request request);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, I think this stuff is all unused in practice and best dropped.

clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
return channel -> client.admin()
.cluster()
.state(clusterStateRequest, new RestToXContentListener<RestClusterGetSettingsResponse>(channel).map(response -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be slightly nicer to use the same ActionListener<ClusterGetSettingsAction.Response> for both the legacy and the regular case, with a .map(clusterState -> new ClusterGetSettingsAction.Response(...)) to do the extra conversion step in the legacy case.

DaveCTurner added a commit to DaveCTurner/elasticsearch that referenced this pull request May 5, 2022
We use the minimum node version in the cluster state to make decisions
about backwards compatibility (e.g. to choose newer actions in the REST
layer only if all nodes will support it). Once the cluster is fully
formed we reject attempts by older nodes to join the cluster so that the
minimum node version only ever increases, which makes
backwards-compatibility decisions safe.

However, it's possible that the REST layer will make decisions about
backwards compatibility before the cluster is fully formed. In this
state, older nodes may still join the cluster and may therefore see
actions that they do not understand.

With this commit we report no nodes to the REST layer until the cluster
is fully-formed, and change the minimum node version in an empty cluster
to be the minimum compatible version. This means the REST layer will
operate in a maximally-compatible mode until the cluster is formed.

Relates elastic#86405
DaveCTurner added a commit that referenced this pull request May 6, 2022
We use the minimum node version in the cluster state to make decisions
about backwards compatibility (e.g. to choose newer actions in the REST
layer only if all nodes will support it). Once the cluster is fully
formed we reject attempts by older nodes to join the cluster so that the
minimum node version only ever increases, which makes
backwards-compatibility decisions safe.

However, it's possible that the REST layer will make decisions about
backwards compatibility before the cluster is fully formed. In this
state, older nodes may still join the cluster and may therefore see
actions that they do not understand.

With this commit we report no nodes to the REST layer until the cluster
is fully-formed, and change the minimum node version in an empty cluster
to be the minimum compatible version. This means the REST layer will
operate in a maximally-compatible mode until the cluster is formed.

Relates #86405
…ttings/ClusterGetSettingsTests.java

Co-authored-by: David Turner <[email protected]>
Copy link
Contributor

@DaveCTurner DaveCTurner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -756,4 +756,5 @@ public interface ClusterAdminClient extends ElasticsearchClient {
* Delete specified dangling indices.
*/
ActionFuture<AcknowledgedResponse> deleteDanglingIndex(DeleteDanglingIndexRequest request);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this file only contains whitespace changes now

ClusterGetSettingsAction.INSTANCE,
clusterSettingsRequest,
new RestToXContentListener<RestClusterGetSettingsResponse>(channel).map(
r -> response(r, renderDefaults, settingsFilter, clusterSettings, settings)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still sort of like to reduce the duplication here between the two branches but I see it's not so simple because we have to consume the request params before we get hold of the channel. Not a blocking suggestion.

@grcevski grcevski merged commit 4b536c6 into elastic:master May 9, 2022
@grcevski grcevski deleted the enhancement/cheaper_settings_request branch May 9, 2022 10:50
@joegallo
Copy link
Contributor

Related to #77466

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Core Core issues without another label >enhancement Team:Core/Infra Meta label for core/infra team v8.3.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RestClusterGetSettingsAction Requests the Full Metadata from Master
5 participants