-
Notifications
You must be signed in to change notification settings - Fork 24.8k
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
ILM migrate data between tiers #61377
Conversation
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)) | ||
) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this 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?
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)) | ||
) |
There was a problem hiding this comment.
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?
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/MigrateAction.java
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/MigrateAction.java
Outdated
Show resolved
Hide resolved
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); |
There was a problem hiding this comment.
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.
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/MigrateAction.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java
Outdated
Show resolved
Hide resolved
@dakrone I think this makes sense |
We already validate the data tier setting values as part of the index settings validation.
We'll have dedicated data tier integration tests that'll have data migration enabled.
…eseries ITS" This reverts commit 6c05591.
@elasticmachine update branch |
@elasticmachine update branch |
expected head sha didn’t match current head ref. |
@elasticmachine update branch |
@elasticmachine update branch |
@elasticmachine update branch |
There was a problem hiding this 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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
logger.debug("[{}] lifecycle action for index [{}] cannot make progress because not all shards are active", | ||
getKey().getAction(), index.getName()); |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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" + |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
@elasticmachine update branch |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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
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]>
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]>
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.
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