-
Notifications
You must be signed in to change notification settings - Fork 25.1k
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
Limit retries of failed allocations per index #18467
Changes from 1 commit
394b280
21887c1
b8d56c7
cb25e79
0aef3d1
4a4436b
6e88223
2544fec
68ad1e0
36aeb55
fd18eeb
6ff6822
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,7 +48,6 @@ public final class UnassignedInfo implements ToXContent, Writeable { | |
public static final Setting<TimeValue> INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING = | ||
Setting.timeSetting("index.unassigned.node_left.delayed_timeout", DEFAULT_DELAYED_NODE_LEFT_TIMEOUT, Property.Dynamic, | ||
Property.IndexScope); | ||
|
||
/** | ||
* Reason why the shard is in unassigned state. | ||
* <p> | ||
|
@@ -103,7 +102,11 @@ public enum Reason { | |
/** | ||
* A better replica location is identified and causes the existing replica allocation to be cancelled. | ||
*/ | ||
REALLOCATED_REPLICA; | ||
REALLOCATED_REPLICA, | ||
/** | ||
* Unassigned as a result of a failed primary while the replica was initializing. | ||
*/ | ||
PRIMARY_FAILED; | ||
} | ||
|
||
private final Reason reason; | ||
|
@@ -112,6 +115,7 @@ public enum Reason { | |
private final long lastComputedLeftDelayNanos; // how long to delay shard allocation, not serialized (always positive, 0 means no delay) | ||
private final String message; | ||
private final Throwable failure; | ||
private final int failedAllocations; | ||
|
||
/** | ||
* creates an UnassingedInfo object based **current** time | ||
|
@@ -120,7 +124,7 @@ public enum Reason { | |
* @param message more information about cause. | ||
**/ | ||
public UnassignedInfo(Reason reason, String message) { | ||
this(reason, message, null, System.nanoTime(), System.currentTimeMillis()); | ||
this(reason, message, null, reason == Reason.ALLOCATION_FAILED ? 1 : 0, System.nanoTime(), System.currentTimeMillis()); | ||
} | ||
|
||
/** | ||
|
@@ -130,13 +134,16 @@ public UnassignedInfo(Reason reason, String message) { | |
* @param unassignedTimeNanos the time to use as the base for any delayed re-assignment calculation | ||
* @param unassignedTimeMillis the time of unassignment used to display to in our reporting. | ||
*/ | ||
public UnassignedInfo(Reason reason, @Nullable String message, @Nullable Throwable failure, long unassignedTimeNanos, long unassignedTimeMillis) { | ||
public UnassignedInfo(Reason reason, @Nullable String message, @Nullable Throwable failure, int failedAllocations, long unassignedTimeNanos, long unassignedTimeMillis) { | ||
this.reason = reason; | ||
this.unassignedTimeMillis = unassignedTimeMillis; | ||
this.unassignedTimeNanos = unassignedTimeNanos; | ||
this.lastComputedLeftDelayNanos = 0L; | ||
this.message = message; | ||
this.failure = failure; | ||
this.failedAllocations = failedAllocations; | ||
assert failedAllocations > 0 && reason == Reason.ALLOCATION_FAILED || failedAllocations == 0 && reason != Reason.ALLOCATION_FAILED: | ||
"failedAllocations: " + 0 + " for reason " + reason; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
assert !(message == null && failure != null) : "provide a message if a failure exception is provided"; | ||
} | ||
|
||
|
@@ -147,17 +154,19 @@ public UnassignedInfo(UnassignedInfo unassignedInfo, long newComputedLeftDelayNa | |
this.lastComputedLeftDelayNanos = newComputedLeftDelayNanos; | ||
this.message = unassignedInfo.message; | ||
this.failure = unassignedInfo.failure; | ||
this.failedAllocations = unassignedInfo.failedAllocations; | ||
} | ||
|
||
public UnassignedInfo(StreamInput in) throws IOException { | ||
this.reason = Reason.values()[(int) in.readByte()]; | ||
this.unassignedTimeMillis = in.readLong(); | ||
// As System.nanoTime() cannot be compared across different JVMs, reset it to now. | ||
// This means that in master failover situations, elapsed delay time is forgotten. | ||
// This means that in master fail-over situations, elapsed delay time is forgotten. | ||
this.unassignedTimeNanos = System.nanoTime(); | ||
this.lastComputedLeftDelayNanos = 0L; | ||
this.message = in.readOptionalString(); | ||
this.failure = in.readThrowable(); | ||
this.failedAllocations = in.readVInt(); | ||
} | ||
|
||
public void writeTo(StreamOutput out) throws IOException { | ||
|
@@ -166,12 +175,18 @@ public void writeTo(StreamOutput out) throws IOException { | |
// Do not serialize unassignedTimeNanos as System.nanoTime() cannot be compared across different JVMs | ||
out.writeOptionalString(message); | ||
out.writeThrowable(failure); | ||
out.writeVInt(failedAllocations); | ||
} | ||
|
||
public UnassignedInfo readFrom(StreamInput in) throws IOException { | ||
return new UnassignedInfo(in); | ||
} | ||
|
||
/** | ||
* Retruns the number of previously failed allocations of this shard. | ||
*/ | ||
public int getNumFailedAllocations() {return failedAllocations;} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some newlines are ok here :-) |
||
|
||
/** | ||
* The reason why the shard is unassigned. | ||
*/ | ||
|
@@ -325,7 +340,11 @@ public String shortSummary() { | |
StringBuilder sb = new StringBuilder(); | ||
sb.append("[reason=").append(reason).append("]"); | ||
sb.append(", at[").append(DATE_TIME_FORMATTER.printer().print(unassignedTimeMillis)).append("]"); | ||
if (failedAllocations > 0) { | ||
sb.append(", failed_attemps[").append(failedAllocations).append("]"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. attemps -> attempts |
||
} | ||
String details = getDetails(); | ||
|
||
if (details != null) { | ||
sb.append(", details[").append(details).append("]"); | ||
} | ||
|
@@ -342,6 +361,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws | |
builder.startObject("unassigned_info"); | ||
builder.field("reason", reason); | ||
builder.field("at", DATE_TIME_FORMATTER.printer().print(unassignedTimeMillis)); | ||
if (failedAllocations > 0) { | ||
builder.field("failed_attemps", failedAllocations); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, attemps -> attempts |
||
} | ||
String details = getDetails(); | ||
if (details != null) { | ||
builder.field("details", details); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* 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.cluster.routing.allocation.decider; | ||
|
||
import org.elasticsearch.cluster.metadata.IndexMetaData; | ||
import org.elasticsearch.cluster.routing.RoutingNode; | ||
import org.elasticsearch.cluster.routing.ShardRouting; | ||
import org.elasticsearch.cluster.routing.UnassignedInfo; | ||
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; | ||
import org.elasticsearch.common.inject.Inject; | ||
import org.elasticsearch.common.settings.Setting; | ||
import org.elasticsearch.common.settings.Settings; | ||
|
||
/** | ||
* An allocation decider that prevents shards from being allocated on any node if the shards allocation has been retried N times without | ||
* success. This means if a shard has been INITIALIZING N times in a row without being moved to STARTED the shard will be ignored until | ||
* the setting for <tt>index.allocation.max_retry</tt> is raised. The default value is <tt>5</tt>. | ||
*/ | ||
public class MaxRetryAllocationDecider extends AllocationDecider { | ||
|
||
public static final Setting<Integer> SETTING_ALLOCATION_MAX_RETRY = Setting.intSetting("index.allocation.max_retry", 5, 0, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personal preference, but I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like @dakrone's suggestion here. |
||
Setting.Property.Dynamic, Setting.Property.IndexScope); | ||
|
||
public static final String NAME = "max_retry"; | ||
|
||
/** | ||
* Initializes a new {@link MaxRetryAllocationDecider} | ||
* | ||
* @param settings {@link Settings} used by this {@link AllocationDecider} | ||
*/ | ||
@Inject | ||
public MaxRetryAllocationDecider(Settings settings) { | ||
super(settings); | ||
} | ||
|
||
@Override | ||
public Decision canAllocate(ShardRouting shardRouting, RoutingAllocation allocation) { | ||
UnassignedInfo unassignedInfo = shardRouting.unassignedInfo(); | ||
if (unassignedInfo != null && unassignedInfo.getNumFailedAllocations() > 0) { | ||
IndexMetaData indexSafe = allocation.metaData().getIndexSafe(shardRouting.index()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just call this variable |
||
int maxRetry = SETTING_ALLOCATION_MAX_RETRY.get(indexSafe.getSettings()); | ||
if (unassignedInfo.getNumFailedAllocations() >= maxRetry) { | ||
return allocation.decision(Decision.NO, NAME, "shard has already failed allocating [" | ||
+ unassignedInfo.getNumFailedAllocations() + "] times"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will it be nice to show the last failure here as well? this will help explain how we got here. |
||
} | ||
} | ||
return allocation.decision(Decision.YES, NAME, "shard has no previous failures"); | ||
} | ||
|
||
@Override | ||
public Decision canAllocate(ShardRouting shardRouting, RoutingNode node, RoutingAllocation allocation) { | ||
return canAllocate(shardRouting, allocation); | ||
} | ||
} |
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.
just
(assert failedAllocations > 0) == (reason == Reason.ALLOCATION_FAILED)
?