Skip to content

Commit 4c63dce

Browse files
committed
Add a hard limit for index.number_of_shard (#20682)
this change adds a hard limit to `index.number_of_shard` that prevents indices from being created that have more than 1024 shards. This is still a huge limit and can only be changed via settings a system property.
1 parent 0e251ae commit 4c63dce

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,25 @@ public static State fromString(String state) {
157157
}
158158
}
159159

160+
static {
161+
final int maxNumShards = Integer.parseInt(System.getProperty("es.index.max_number_of_shards", "1024"));
162+
if (maxNumShards < 1) {
163+
throw new IllegalArgumentException("es.index.max_number_of_shards must be > 0");
164+
}
165+
MAX_NUMBER_OF_SHARDS = maxNumShards;
166+
}
167+
/* This is a safety limit that should only be exceeded in very rare and special cases. The assumption is that
168+
* 99% of the users have less than 1024 shards per index. We also make it a hard check that requires restart of nodes
169+
* if a cluster should allow to create more than 1024 shards per index. NOTE: this does not limit the number of shards per cluster.
170+
* this also prevents creating stuff like a new index with millions of shards by accident which essentially kills the entire cluster
171+
* with OOM on the spot.*/
172+
private static final int MAX_NUMBER_OF_SHARDS;
173+
160174
public static final String INDEX_SETTING_PREFIX = "index.";
161175
public static final String SETTING_NUMBER_OF_SHARDS = "index.number_of_shards";
162176
public static final Setting<Integer> INDEX_NUMBER_OF_SHARDS_SETTING =
163-
Setting.intSetting(SETTING_NUMBER_OF_SHARDS, 5, 1, Property.IndexScope);
177+
Setting.intSetting(SETTING_NUMBER_OF_SHARDS, Math.min(5, MAX_NUMBER_OF_SHARDS), 1, MAX_NUMBER_OF_SHARDS,
178+
Property.IndexScope);
164179
public static final String SETTING_NUMBER_OF_REPLICAS = "index.number_of_replicas";
165180
public static final Setting<Integer> INDEX_NUMBER_OF_REPLICAS_SETTING =
166181
Setting.intSetting(SETTING_NUMBER_OF_REPLICAS, 1, 0, Property.Dynamic, Property.IndexScope);

docs/reference/index-modules.asciidoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ specific index module:
3838

3939
The number of primary shards that an index should have. Defaults to 5.
4040
This setting can only be set at index creation time. It cannot be
41-
changed on a closed index.
41+
changed on a closed index. Note: the number of shards are limited to `1024` per
42+
index. This limitation is a safety limit to prevent accidental creation of indices
43+
that can destabilize a cluster due to resource allocation. The limit can be modified
44+
by specifying `export ES_JAVA_OPTS="-Des.index.max_number_of_shards=128"` system property on every node that is
45+
part of the cluster.
4246

4347
`index.shard.check_on_startup`::
4448
+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.bootstrap;
20+
21+
import org.elasticsearch.cluster.metadata.IndexMetaData;
22+
import org.elasticsearch.common.SuppressForbidden;
23+
import org.elasticsearch.common.settings.Settings;
24+
import org.elasticsearch.test.ESTestCase;
25+
26+
public class EvilSystemPropertyTests extends ESTestCase {
27+
28+
@SuppressForbidden(reason = "manipulates system properties for testing")
29+
public void testMaxNumShards() {
30+
int limit = randomIntBetween(1, 10);
31+
System.setProperty("es.index.max_number_of_shards", Integer.toString(limit));
32+
try {
33+
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () ->
34+
IndexMetaData.INDEX_NUMBER_OF_SHARDS_SETTING
35+
.get(Settings.builder().put("index.number_of_shards", 11).build()));
36+
assertEquals("Failed to parse value [11] for setting [index.number_of_shards] must be <= " + limit, exception.getMessage());
37+
} finally {
38+
System.clearProperty("es.index.max_number_of_shards");
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)