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

ILM migrate data between tiers #61377

Merged
merged 42 commits into from
Sep 17, 2020

Conversation

andreidan
Copy link
Contributor

@andreidan andreidan commented Aug 20, 2020

This adds ILM support for automatically migrating the managed
indices between data tiers.

This proposal makes use of a MigrateAction that is injected
(similar to how the Unfollow action is injected) in phases that
don't define index allocation rules using the AllocateAction or
don't explicitly define the MigrateAction itself (regardless if it's
enabled or disabled).

Relates to #60848

Comment on lines 56 to 61
private static final AllocationDeciders ALLOCATION_DECIDERS = new AllocationDeciders(
List.of(
new FilterAllocationDecider(Settings.EMPTY, new ClusterSettings(Settings.EMPTY,
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS)),
new DataTierAllocationDecider(new ClusterSettings(Settings.EMPTY, ALL_CLUSTER_SETTINGS))
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we make this configurable and serializable for the step? (ie. use just the one allocation decider depending on where it is used)
I'd say we want a fully allocated index so verifying both always is alright. What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm... I actually think that we may want to split checking the allocation for the migrate action into a separate step. For example, the allocation routed step currently has a pretty generic message (Waiting for [n] shards to be allocated to nodes matching the given filters). I think if we split this into a new MigrationRouted step we could give it a much better explanation, for example, something like:

waiting [23m] for [3] shards to be allocated on nodes with the [data_warm] tier

additionally, I think we could also even throw an error to signal to the user when things were in a bad state, something like:

exception waiting for index to be moved to the [data_cold] tier, there are currently no [data_cold] nodes in the cluster

Then the step could be retryable (so we check every 10 minutes) and it at least gives us a way of signaling to a user (alerting on the ilm-history index for example) when they are in an irreconcilable position and need to adjust their cluster.

What do you think?

Copy link
Contributor Author

@andreidan andreidan Aug 21, 2020

Choose a reason for hiding this comment

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

You make a great point on validating if the cluster has any node with a particular role available. I'll create another step for the migrate action (the nicer messages will be a great UX improvement as well)

public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
if (enabled) {
Map<String, String> include = Map.of("_tier", "data_" + phase);
AllocateAction migrateDataAction = new AllocateAction(null, include, null, null);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should we remove the possible_require and _exclude settings (which might've been set manually before) to make sure they don't invalidate the "migrate to the next data tier" goal?

Copy link
Member

Choose a reason for hiding this comment

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

That's a good question, I'm not sure we'd want to piecemeal remove all of them, because they could be something for an additional attribute that we want to preserve between phases.

I will have to think on it a bit, it also makes me wonder whether we should make it configurable whether all other index-level allocation filtering settings are removed/preserved when doing the migration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's an interesting one - we do not allow to have the migrate action enabled in a phase that has the allocate action (configuring allocation), so maybe it makes sense for the migrate action to invalidate the possible allocation filterings the index might have (for eg. from a previous phase where the migrate action was disabled and the allocation action was configured)

@dakrone dakrone self-requested a review August 20, 2020 19:23
Copy link
Member

@dakrone dakrone left a comment

Choose a reason for hiding this comment

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

Thanks for working on this Andrei! I left some thoughts on the implementation.

I also was thinking/wondering, is this something we think should have an index level opt-out setting? I'm thinking of our internal indices where we might be using an ILM policy but don't know the topology of the cluster (and honestly don't care about it living on a specific data tier).

I am also wondering if maybe should have the setting be a more generic "opt out of automatic tier management" that would opt out of allocating on hot nodes by default. We could then potentially use this setting for internal indices that we don't want to have to worry about, like .security or .kibana.

What do you think?

Comment on lines 56 to 61
private static final AllocationDeciders ALLOCATION_DECIDERS = new AllocationDeciders(
List.of(
new FilterAllocationDecider(Settings.EMPTY, new ClusterSettings(Settings.EMPTY,
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS)),
new DataTierAllocationDecider(new ClusterSettings(Settings.EMPTY, ALL_CLUSTER_SETTINGS))
)
Copy link
Member

Choose a reason for hiding this comment

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

Hmm... I actually think that we may want to split checking the allocation for the migrate action into a separate step. For example, the allocation routed step currently has a pretty generic message (Waiting for [n] shards to be allocated to nodes matching the given filters). I think if we split this into a new MigrationRouted step we could give it a much better explanation, for example, something like:

waiting [23m] for [3] shards to be allocated on nodes with the [data_warm] tier

additionally, I think we could also even throw an error to signal to the user when things were in a bad state, something like:

exception waiting for index to be moved to the [data_cold] tier, there are currently no [data_cold] nodes in the cluster

Then the step could be retryable (so we check every 10 minutes) and it at least gives us a way of signaling to a user (alerting on the ilm-history index for example) when they are in an irreconcilable position and need to adjust their cluster.

What do you think?

public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
if (enabled) {
Map<String, String> include = Map.of("_tier", "data_" + phase);
AllocateAction migrateDataAction = new AllocateAction(null, include, null, null);
Copy link
Member

Choose a reason for hiding this comment

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

That's a good question, I'm not sure we'd want to piecemeal remove all of them, because they could be something for an additional attribute that we want to preserve between phases.

I will have to think on it a bit, it also makes me wonder whether we should make it configurable whether all other index-level allocation filtering settings are removed/preserved when doing the migration.

@andreidan
Copy link
Contributor Author

I am also wondering if maybe should have the setting be a more generic "opt out of automatic tier management" that would opt out of allocating on hot nodes by default

@dakrone I think this makes sense

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

@elasticmachine
Copy link
Collaborator

expected head sha didn’t match current head ref.

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

Copy link
Member

@dakrone dakrone left a comment

Choose a reason for hiding this comment

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

Awesome, this is looking really close, I left one comment about the execution order (I think 'allocate' should come before 'migrate') and a few other really really minor quibbilings, but nothing major

FreezeAction.NAME, SearchableSnapshotAction.NAME);
static final List<String> ORDERED_VALID_FROZEN_ACTIONS = Arrays.asList(SetPriorityAction.NAME, UnfollowAction.NAME, AllocateAction.NAME,
FreezeAction.NAME, SearchableSnapshotAction.NAME);
MigrateAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME);
Copy link
Member

Choose a reason for hiding this comment

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

I realized something about this, I think we should do AllocateAction prior to the migrate action, or else we are liable to get "stuck".

For example, if a user had multiple hot nodes and only a single warm node, we would try to migrate an index with one replica from hot to warm, but the replica could never allocate, since there is only a single node. Instead, we should do the allocate action first (where a user could set number_of_replicas to 0) before migrating to the next tier.

What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I also realize we can get stuck the opposite way too, so either way it's possible to get stuck, but I think that doing allocate first is still the way we should go. Curious about what you think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You make a great point Lee. I think we should go forward this way as it also keeps the "number of replicas is modified before the allocations change" behaviour consistent with how the allocate action works.

Maybe it's a bit more of a future talk, but I do wonder if it'd be a good time to extract the "change number of replicas" into its own action. I think being conflated with the allocation rules in the allocate action is generally confusing, but even more so now where we'd expect the users to use both the allocate and the migrate (admittedly, not necessarily explicitly declaring it) actions to achieve the "reduce number of replicas and then relocate index" scenario.
I think a change-replicas-number action would be welcome at this stage.

Comment on lines 75 to 76
logger.debug("[{}] lifecycle action for index [{}] cannot make progress because not all shards are active",
getKey().getAction(), index.getName());
Copy link
Member

Choose a reason for hiding this comment

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

I think in this one we can be more specific in the debug message, so perhaps:

[check-migration] migration for index [foo] to the [data_cold] tier cannot progress, as not all shards are active

(we can pull the tier name from the index setting)

logger.debug(statusMessage);
return new Result(false, new AllocationInfo(idxMeta.getNumberOfReplicas(), allocationPendingAllShards, true, statusMessage));
} else {
logger.debug("{} lifecycle action for [{}] complete", index, getKey().getAction());
Copy link
Member

Choose a reason for hiding this comment

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

same here about log messages, perhaps:

[check-migration] migration of index [foo] to tier [data_cold] complete

It's definitely a lot nicer to grep for in logs :)

* Builds the AllocationInfo representing a cluster state with a routing table that has all the shards active for a particular index
* but there are still {@link #numberShardsLeftToAllocate} left to be allocated.
*/
public static AllocationInfo allShardsActiveAllocationInfo(long actualReplicas, long numberShardsLeftToAllocate) {
Copy link
Member

Choose a reason for hiding this comment

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

Super minor, but it's confusing to call the parameter here (and in the function above) "actualReplicas", it makes it seem like there should be a "allocatedReplicas" parameter somewhere as well. Maybe we can just call in numReplicas?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Totally, my grep skills failed me.

.collect(Collectors.joining(","));
if (Strings.hasText(phasesWithConflictingMigrationActions)) {
throw new IllegalArgumentException("phases [" + phasesWithConflictingMigrationActions + "] specify an enabled " +
MigrateAction.NAME + " action and the " + AllocateAction.NAME + " action. specify only one data migration action in these" +
Copy link
Member

Choose a reason for hiding this comment

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

I think rather than:

phases [warm,cold] specify an enabled migrate action and the allocate action. specify only one data migration action in these phases

We should clarify that it's the actual allocation rules that cause problems (they're free to adjust replica count as much as they'd like):

phase [warm,cold] specifies an enabled migrate action and an allocate action with allocation rules, specify only a single data migration in each phase

});

logger.info("starting cold data node");
internalCluster().startNode(coldNode(Settings.EMPTY));
Copy link
Member

Choose a reason for hiding this comment

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

Should we have the check for "cold" node allocation before starting up the frozen node? We have it for the other phases, so probably best to check for it just so it doesn't end up disappearing for only the cold phase some time in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, changed to wait for the complete step in the cold phase (removed the frozen node and checks)

@andreidan
Copy link
Contributor Author

@elasticmachine update branch

Copy link
Member

@dakrone dakrone left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for iterating on this Andrei! I left one more minor comment, but it's pretty small


@Override
public int hashCode() {
return 711;
Copy link
Member

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 incorporate super.hashCode() or else the hash code will be the same regardless of stepkeys

@andreidan andreidan merged commit c1746af into elastic:master Sep 17, 2020
andreidan added a commit to andreidan/elasticsearch that referenced this pull request Sep 17, 2020
This adds ILM support for automatically migrating the managed
indices between data tiers.

This proposal makes use of a MigrateAction that is injected
(similar to how the Unfollow action is injected) in phases that
don't define index allocation rules using the AllocateAction or
don't explicitly define the MigrateAction itself (regardless if it's
enabled or disabled).

(cherry picked from commit c1746af)
Signed-off-by: Andrei Dan <[email protected]>
andreidan added a commit that referenced this pull request Sep 17, 2020
This adds ILM support for automatically migrating the managed
indices between data tiers.

This proposal makes use of a MigrateAction that is injected
(similar to how the Unfollow action is injected) in phases that
don't define index allocation rules using the AllocateAction or
don't explicitly define the MigrateAction itself (regardless if it's
enabled or disabled).

(cherry picked from commit c1746af)
Signed-off-by: Andrei Dan <[email protected]>
elasticsearchmachine pushed a commit that referenced this pull request Sep 15, 2022
In #61377 we introduced a feature to let ILM migrate data between tiers.
We achived this by inject a MigrateAction in `warm` and `cold` phase.
However we also injected this action to phases where it is not supported
such as `hot`, `frozen` and `delete` phase. It's better to no inject
MigrateAction even though MigrateAction in these phases will be filtered
out in `TimeseriesLifecycleType#getOrderedActions(Phase)` . This pr
updates the
`TimeseriesLifecycleType#shouldInjectMigrateStepForPhase(Phase)` to not
inject MigrateAction for phase in which MigrateAction is not supported.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Data Management/ILM+SLM Index and Snapshot lifecycle management >feature Team:Data Management Meta label for data/management team v7.10.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants