Skip to content

Commit dc166c5

Browse files
author
Ali Beyad
authored
Process more expensive allocation deciders last (#20724)
Today, the individual allocation deciders appear in random order when initialized in AllocationDeciders, which means potentially more performance intensive allocation deciders could run before less expensive deciders. This adds to the execution time when a less expensive decider could terminate the decision making process early with a NO decision. This commit orders the initialization of allocation deciders, based on a general assessment of the big O runtime of each decider, moving the likely more expensive deciders last. Closes #12815
1 parent 3dcf1d5 commit dc166c5

File tree

2 files changed

+54
-16
lines changed

2 files changed

+54
-16
lines changed

core/src/main/java/org/elasticsearch/cluster/ClusterModule.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@
1919

2020
package org.elasticsearch.cluster;
2121

22-
import org.apache.logging.log4j.Logger;
2322
import org.elasticsearch.cluster.action.index.MappingUpdatedAction;
2423
import org.elasticsearch.cluster.action.index.NodeMappingRefreshAction;
2524
import org.elasticsearch.cluster.action.shard.ShardStateAction;
2625
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
27-
import org.elasticsearch.cluster.metadata.IndexTemplateFilter;
2826
import org.elasticsearch.cluster.metadata.MetaDataCreateIndexService;
2927
import org.elasticsearch.cluster.metadata.MetaDataDeleteIndexService;
3028
import org.elasticsearch.cluster.metadata.MetaDataIndexAliasesService;
@@ -55,18 +53,17 @@
5553
import org.elasticsearch.cluster.routing.allocation.decider.ThrottlingAllocationDecider;
5654
import org.elasticsearch.cluster.service.ClusterService;
5755
import org.elasticsearch.common.inject.AbstractModule;
58-
import org.elasticsearch.common.logging.Loggers;
5956
import org.elasticsearch.common.settings.ClusterSettings;
6057
import org.elasticsearch.common.settings.Setting;
6158
import org.elasticsearch.common.settings.Setting.Property;
6259
import org.elasticsearch.common.settings.Settings;
63-
import org.elasticsearch.common.util.ExtensionPoint;
6460
import org.elasticsearch.gateway.GatewayAllocator;
6561
import org.elasticsearch.plugins.ClusterPlugin;
6662
import org.elasticsearch.tasks.TaskResultsService;
6763

6864
import java.util.Collection;
6965
import java.util.HashMap;
66+
import java.util.LinkedHashMap;
7067
import java.util.List;
7168
import java.util.Map;
7269
import java.util.Objects;
@@ -109,21 +106,21 @@ public IndexNameExpressionResolver getIndexNameExpressionResolver() {
109106
public static Collection<AllocationDecider> createAllocationDeciders(Settings settings, ClusterSettings clusterSettings,
110107
List<ClusterPlugin> clusterPlugins) {
111108
// collect deciders by class so that we can detect duplicates
112-
Map<Class, AllocationDecider> deciders = new HashMap<>();
109+
Map<Class, AllocationDecider> deciders = new LinkedHashMap<>();
113110
addAllocationDecider(deciders, new MaxRetryAllocationDecider(settings));
114-
addAllocationDecider(deciders, new SameShardAllocationDecider(settings));
115-
addAllocationDecider(deciders, new FilterAllocationDecider(settings, clusterSettings));
116111
addAllocationDecider(deciders, new ReplicaAfterPrimaryActiveAllocationDecider(settings));
117-
addAllocationDecider(deciders, new ThrottlingAllocationDecider(settings, clusterSettings));
118112
addAllocationDecider(deciders, new RebalanceOnlyWhenActiveAllocationDecider(settings));
119113
addAllocationDecider(deciders, new ClusterRebalanceAllocationDecider(settings, clusterSettings));
120114
addAllocationDecider(deciders, new ConcurrentRebalanceAllocationDecider(settings, clusterSettings));
121115
addAllocationDecider(deciders, new EnableAllocationDecider(settings, clusterSettings));
122-
addAllocationDecider(deciders, new AwarenessAllocationDecider(settings, clusterSettings));
123-
addAllocationDecider(deciders, new ShardsLimitAllocationDecider(settings, clusterSettings));
124116
addAllocationDecider(deciders, new NodeVersionAllocationDecider(settings));
125-
addAllocationDecider(deciders, new DiskThresholdDecider(settings, clusterSettings));
126117
addAllocationDecider(deciders, new SnapshotInProgressAllocationDecider(settings, clusterSettings));
118+
addAllocationDecider(deciders, new FilterAllocationDecider(settings, clusterSettings));
119+
addAllocationDecider(deciders, new SameShardAllocationDecider(settings));
120+
addAllocationDecider(deciders, new DiskThresholdDecider(settings, clusterSettings));
121+
addAllocationDecider(deciders, new ThrottlingAllocationDecider(settings, clusterSettings));
122+
addAllocationDecider(deciders, new ShardsLimitAllocationDecider(settings, clusterSettings));
123+
addAllocationDecider(deciders, new AwarenessAllocationDecider(settings, clusterSettings));
127124

128125
clusterPlugins.stream()
129126
.flatMap(p -> p.createAllocationDeciders(settings, clusterSettings).stream())

core/src/test/java/org/elasticsearch/cluster/ClusterModuleTests.java

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,25 @@
1919

2020
package org.elasticsearch.cluster;
2121

22-
import org.elasticsearch.action.admin.indices.create.CreateIndexClusterStateUpdateRequest;
23-
import org.elasticsearch.cluster.metadata.IndexTemplateFilter;
24-
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
2522
import org.elasticsearch.cluster.node.DiscoveryNode;
2623
import org.elasticsearch.cluster.routing.ShardRouting;
2724
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
28-
import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator;
2925
import org.elasticsearch.cluster.routing.allocation.allocator.ShardsAllocator;
3026
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDecider;
31-
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
27+
import org.elasticsearch.cluster.routing.allocation.decider.AwarenessAllocationDecider;
28+
import org.elasticsearch.cluster.routing.allocation.decider.ClusterRebalanceAllocationDecider;
29+
import org.elasticsearch.cluster.routing.allocation.decider.ConcurrentRebalanceAllocationDecider;
30+
import org.elasticsearch.cluster.routing.allocation.decider.DiskThresholdDecider;
3231
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
32+
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
33+
import org.elasticsearch.cluster.routing.allocation.decider.MaxRetryAllocationDecider;
34+
import org.elasticsearch.cluster.routing.allocation.decider.NodeVersionAllocationDecider;
35+
import org.elasticsearch.cluster.routing.allocation.decider.RebalanceOnlyWhenActiveAllocationDecider;
36+
import org.elasticsearch.cluster.routing.allocation.decider.ReplicaAfterPrimaryActiveAllocationDecider;
37+
import org.elasticsearch.cluster.routing.allocation.decider.SameShardAllocationDecider;
38+
import org.elasticsearch.cluster.routing.allocation.decider.ShardsLimitAllocationDecider;
39+
import org.elasticsearch.cluster.routing.allocation.decider.SnapshotInProgressAllocationDecider;
40+
import org.elasticsearch.cluster.routing.allocation.decider.ThrottlingAllocationDecider;
3341
import org.elasticsearch.cluster.service.ClusterService;
3442
import org.elasticsearch.common.inject.ModuleTestCase;
3543
import org.elasticsearch.common.settings.ClusterSettings;
@@ -40,9 +48,12 @@
4048
import org.elasticsearch.common.settings.SettingsModule;
4149
import org.elasticsearch.plugins.ClusterPlugin;
4250

51+
import java.util.Arrays;
4352
import java.util.Collection;
4453
import java.util.Collections;
4554
import java.util.HashMap;
55+
import java.util.Iterator;
56+
import java.util.List;
4657
import java.util.Map;
4758
import java.util.function.Supplier;
4859

@@ -156,4 +167,34 @@ public void testShardsAllocatorFactoryNull() {
156167
NullPointerException e = expectThrows(NullPointerException.class, () ->
157168
newClusterModuleWithShardsAllocator(settings, "bad", () -> null));
158169
}
170+
171+
// makes sure that the allocation deciders are setup in the correct order, such that the
172+
// slower allocation deciders come last and we can exit early if there is a NO decision without
173+
// running them. If the order of the deciders is changed for a valid reason, the order should be
174+
// changed in the test too.
175+
public void testAllocationDeciderOrder() {
176+
List<Class<? extends AllocationDecider>> expectedDeciders = Arrays.asList(
177+
MaxRetryAllocationDecider.class,
178+
ReplicaAfterPrimaryActiveAllocationDecider.class,
179+
RebalanceOnlyWhenActiveAllocationDecider.class,
180+
ClusterRebalanceAllocationDecider.class,
181+
ConcurrentRebalanceAllocationDecider.class,
182+
EnableAllocationDecider.class,
183+
NodeVersionAllocationDecider.class,
184+
SnapshotInProgressAllocationDecider.class,
185+
FilterAllocationDecider.class,
186+
SameShardAllocationDecider.class,
187+
DiskThresholdDecider.class,
188+
ThrottlingAllocationDecider.class,
189+
ShardsLimitAllocationDecider.class,
190+
AwarenessAllocationDecider.class);
191+
Collection<AllocationDecider> deciders = ClusterModule.createAllocationDeciders(Settings.EMPTY,
192+
new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), Collections.emptyList());
193+
Iterator<AllocationDecider> iter = deciders.iterator();
194+
int idx = 0;
195+
while (iter.hasNext()) {
196+
AllocationDecider decider = iter.next();
197+
assertSame(decider.getClass(), expectedDeciders.get(idx++));
198+
}
199+
}
159200
}

0 commit comments

Comments
 (0)