Skip to content

Commit 2e4e8fe

Browse files
committed
Introduce a new search node role to hold search only shards (opensearch-project#17620)
* Introduce a new search node role Signed-off-by: Vinay Krishna Pudyodu <[email protected]> * Add changelog Signed-off-by: Vinay Krishna Pudyodu <[email protected]> * fixed PR comments Signed-off-by: Vinay Krishna Pudyodu <[email protected]> * rename search to warm in FsProbe test Signed-off-by: Vinay Krishna Pudyodu <[email protected]> * fixed ClusterStatsIT tests Signed-off-by: Vinay Krishna Pudyodu <[email protected]> * added ClusterStatsIT test for search node role Signed-off-by: Vinay Krishna Pudyodu <[email protected]> --------- Signed-off-by: Vinay Krishna Pudyodu <[email protected]>
1 parent 79fd042 commit 2e4e8fe

File tree

9 files changed

+132
-10
lines changed

9 files changed

+132
-10
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77
### Added
88
- Change priority for scheduling reroute during timeout([#16445](https://github.com/opensearch-project/OpenSearch/pull/16445))
99
- Renaming the node role search to warm ([#17573](https://github.com/opensearch-project/OpenSearch/pull/17573))
10+
- Introduce a new search node role to hold search only shards ([#17620](https://github.com/opensearch-project/OpenSearch/pull/17620))
1011
- Search Replica Allocation and Recovery ([#17457](https://github.com/opensearch-project/OpenSearch/pull/17457))
1112

1213
### Dependencies

server/src/internalClusterTest/java/org/opensearch/action/admin/cluster/stats/ClusterStatsIT.java

+32-7
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private void waitForNodes(int numNodes) {
9090
public void testNodeCounts() {
9191
int total = 1;
9292
internalCluster().startNode();
93-
Map<String, Integer> expectedCounts = getExpectedCounts(1, 1, 1, 1, 1, 0, 0);
93+
Map<String, Integer> expectedCounts = getExpectedCounts(1, 1, 1, 1, 1, 0, 0, 0);
9494
int numNodes = randomIntBetween(1, 5);
9595

9696
ClusterStatsResponse response = client().admin()
@@ -159,7 +159,7 @@ public void testNodeCountsWithDeprecatedMasterRole() throws ExecutionException,
159159
internalCluster().startNode(settings);
160160
waitForNodes(total);
161161

162-
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 0, 0, 0);
162+
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 0, 0, 0, 0);
163163

164164
Client client = client();
165165
ClusterStatsResponse response = client.admin()
@@ -484,7 +484,7 @@ public void testNodeRolesWithMasterLegacySettings() throws ExecutionException, I
484484
internalCluster().startNodes(legacyMasterSettings);
485485
waitForNodes(total);
486486

487-
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 1, 0, 0);
487+
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 1, 0, 0, 0);
488488

489489
Client client = client();
490490
ClusterStatsResponse clusterStatsResponse = client.admin()
@@ -518,7 +518,7 @@ public void testNodeRolesWithClusterManagerRole() throws ExecutionException, Int
518518
internalCluster().startNodes(clusterManagerNodeRoleSettings);
519519
waitForNodes(total);
520520

521-
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 1, 0, 0);
521+
Map<String, Integer> expectedCounts = getExpectedCounts(0, 1, 1, 0, 1, 0, 0, 0);
522522

523523
Client client = client();
524524
ClusterStatsResponse clusterStatsResponse = client.admin()
@@ -546,7 +546,7 @@ public void testNodeRolesWithSeedDataNodeLegacySettings() throws ExecutionExcept
546546
internalCluster().startNodes(legacySeedDataNodeSettings);
547547
waitForNodes(total);
548548

549-
Map<String, Integer> expectedRoleCounts = getExpectedCounts(1, 1, 1, 0, 1, 0, 0);
549+
Map<String, Integer> expectedRoleCounts = getExpectedCounts(1, 1, 1, 0, 1, 0, 0, 0);
550550

551551
Client client = client();
552552
ClusterStatsResponse clusterStatsResponse = client.admin()
@@ -577,7 +577,7 @@ public void testNodeRolesWithDataNodeLegacySettings() throws ExecutionException,
577577
internalCluster().startNodes(legacyDataNodeSettings);
578578
waitForNodes(total);
579579

580-
Map<String, Integer> expectedRoleCounts = getExpectedCounts(1, 1, 1, 0, 1, 0, 0);
580+
Map<String, Integer> expectedRoleCounts = getExpectedCounts(1, 1, 1, 0, 1, 0, 0, 0);
581581

582582
Client client = client();
583583
ClusterStatsResponse clusterStatsResponse = client.admin()
@@ -594,6 +594,29 @@ public void testNodeRolesWithDataNodeLegacySettings() throws ExecutionException,
594594
assertEquals(expectedNodesRoles, Set.of(getNodeRoles(client, 0), getNodeRoles(client, 1)));
595595
}
596596

597+
public void testNodeRolesWithSearchNode() throws ExecutionException, InterruptedException {
598+
int total = 2;
599+
internalCluster().startClusterManagerOnlyNodes(1);
600+
internalCluster().startSearchOnlyNode();
601+
waitForNodes(total);
602+
603+
Map<String, Integer> expectedRoleCounts = getExpectedCounts(0, 1, 1, 0, 0, 0, 1, 0);
604+
605+
Client client = client();
606+
ClusterStatsResponse clusterStatsResponse = client.admin()
607+
.cluster()
608+
.prepareClusterStats()
609+
.useAggregatedNodeLevelResponses(randomBoolean())
610+
.get();
611+
assertCounts(clusterStatsResponse.getNodesStats().getCounts(), total, expectedRoleCounts);
612+
613+
Set<Set<String>> expectedNodesRoles = Set.of(
614+
Set.of(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName()),
615+
Set.of(DiscoveryNodeRole.SEARCH_ROLE.roleName())
616+
);
617+
assertEquals(expectedNodesRoles, Set.of(getNodeRoles(client, 0), getNodeRoles(client, 1)));
618+
}
619+
597620
public void testClusterStatsWithNodeMetricsFilter() {
598621
internalCluster().startNode();
599622
ensureGreen();
@@ -887,6 +910,7 @@ private Map<String, Integer> getExpectedCounts(
887910
int clusterManagerRoleCount,
888911
int ingestRoleCount,
889912
int remoteClusterClientRoleCount,
913+
int warmRoleCount,
890914
int searchRoleCount,
891915
int coordinatingOnlyCount
892916
) {
@@ -896,7 +920,8 @@ private Map<String, Integer> getExpectedCounts(
896920
expectedCounts.put(DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName(), clusterManagerRoleCount);
897921
expectedCounts.put(DiscoveryNodeRole.INGEST_ROLE.roleName(), ingestRoleCount);
898922
expectedCounts.put(DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE.roleName(), remoteClusterClientRoleCount);
899-
expectedCounts.put(DiscoveryNodeRole.WARM_ROLE.roleName(), searchRoleCount);
923+
expectedCounts.put(DiscoveryNodeRole.WARM_ROLE.roleName(), warmRoleCount);
924+
expectedCounts.put(DiscoveryNodeRole.SEARCH_ROLE.roleName(), searchRoleCount);
900925
expectedCounts.put(ClusterStatsNodes.Counts.COORDINATING_ONLY, coordinatingOnlyCount);
901926
return expectedCounts;
902927
}

server/src/main/java/org/opensearch/cluster/node/DiscoveryNode.java

+9
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,15 @@ public boolean isWarmNode() {
490490
return roles.contains(DiscoveryNodeRole.WARM_ROLE);
491491
}
492492

493+
/**
494+
* Returns whether the node is dedicated to host search replicas.
495+
*
496+
* @return true if the node contains a search role, false otherwise
497+
*/
498+
public boolean isSearchNode() {
499+
return roles.contains(DiscoveryNodeRole.SEARCH_ROLE);
500+
}
501+
493502
/**
494503
* Returns whether the node is a remote store node.
495504
*

server/src/main/java/org/opensearch/cluster/node/DiscoveryNodeRole.java

+29-1
Original file line numberDiff line numberDiff line change
@@ -310,11 +310,39 @@ public Setting<Boolean> legacySetting() {
310310

311311
};
312312

313+
/**
314+
* Represents the role for a search node, which is dedicated to host search replicas.
315+
*/
316+
public static final DiscoveryNodeRole SEARCH_ROLE = new DiscoveryNodeRole("search", "s", true) {
317+
318+
@Override
319+
public Setting<Boolean> legacySetting() {
320+
// search role is added in 2.4 so doesn't need to configure legacy setting
321+
return null;
322+
}
323+
324+
@Override
325+
public void validateRole(List<DiscoveryNodeRole> roles) {
326+
for (DiscoveryNodeRole role : roles) {
327+
if (role.equals(DiscoveryNodeRole.SEARCH_ROLE) == false) {
328+
throw new IllegalArgumentException(
329+
String.format(
330+
Locale.ROOT,
331+
"%s role cannot be combined with any other role on a node.",
332+
DiscoveryNodeRole.SEARCH_ROLE.roleName()
333+
)
334+
);
335+
}
336+
}
337+
}
338+
339+
};
340+
313341
/**
314342
* The built-in node roles.
315343
*/
316344
public static SortedSet<DiscoveryNodeRole> BUILT_IN_ROLES = Collections.unmodifiableSortedSet(
317-
new TreeSet<>(Arrays.asList(DATA_ROLE, INGEST_ROLE, CLUSTER_MANAGER_ROLE, REMOTE_CLUSTER_CLIENT_ROLE, WARM_ROLE))
345+
new TreeSet<>(Arrays.asList(DATA_ROLE, INGEST_ROLE, CLUSTER_MANAGER_ROLE, REMOTE_CLUSTER_CLIENT_ROLE, WARM_ROLE, SEARCH_ROLE))
318346
);
319347

320348
/**

server/src/test/java/org/opensearch/cluster/node/DiscoveryNodeTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,14 @@ public void testDiscoveryNodeIsWarmUnset() {
242242
runTestDiscoveryNodeIsWarm(nonWarmNode(), false);
243243
}
244244

245+
public void testDiscoveryNodeIsSearchSet() {
246+
runTestDiscoveryNodeIsSearch(NodeRoles.searchOnlyNode(), true);
247+
}
248+
249+
public void testDiscoveryNodeIsSearchUnset() {
250+
runTestDiscoveryNodeIsSearch(NodeRoles.nonSearchNode(), false);
251+
}
252+
245253
// Added in 2.0 temporarily, validate the MASTER_ROLE is in the list of known roles.
246254
// MASTER_ROLE was removed from BUILT_IN_ROLES and is imported by setDeprecatedMasterRole(),
247255
// as a workaround for making the new CLUSTER_MANAGER_ROLE has got the same abbreviation 'm'.
@@ -271,6 +279,16 @@ private void runTestDiscoveryNodeIsWarm(final Settings settings, final boolean e
271279
}
272280
}
273281

282+
private void runTestDiscoveryNodeIsSearch(final Settings settings, final boolean expected) {
283+
final DiscoveryNode node = DiscoveryNode.createLocal(settings, new TransportAddress(TransportAddress.META_ADDRESS, 9200), "node");
284+
assertThat(node.isSearchNode(), equalTo(expected));
285+
if (expected) {
286+
assertThat(node.getRoles(), hasItem(DiscoveryNodeRole.SEARCH_ROLE));
287+
} else {
288+
assertThat(node.getRoles(), not(hasItem(DiscoveryNodeRole.SEARCH_ROLE)));
289+
}
290+
}
291+
274292
public void testGetRoleFromRoleNameIsCaseInsensitive() {
275293
String dataRoleName = "DATA";
276294
DiscoveryNodeRole dataNodeRole = DiscoveryNode.getRoleFromRoleName(dataRoleName);

server/src/test/java/org/opensearch/monitor/fs/FsProbeTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public void testFsInfo() throws IOException {
126126
}
127127

128128
public void testFsCacheInfo() throws IOException {
129-
Settings settings = Settings.builder().put("node.roles", "search").build();
129+
Settings settings = Settings.builder().put("node.roles", "warm").build();
130130
try (NodeEnvironment env = newNodeEnvironment(settings)) {
131131
ByteSizeValue gbByteSizeValue = new ByteSizeValue(1, ByteSizeUnit.GB);
132132
env.fileCacheNodePath().fileCacheReservedSize = gbByteSizeValue;
@@ -164,7 +164,7 @@ public void testFsCacheInfo() throws IOException {
164164
}
165165

166166
public void testFsInfoWhenFileCacheOccupied() throws IOException {
167-
Settings settings = Settings.builder().putList("node.roles", "search", "data").build();
167+
Settings settings = Settings.builder().putList("node.roles", "warm", "data").build();
168168
try (NodeEnvironment env = newNodeEnvironment(settings)) {
169169
// Use the total space as reserved space to simulate the situation where the cache space is occupied
170170
final long totalSpace = adjustForHugeFilesystems(env.fileCacheNodePath().fileStore.getTotalSpace());

server/src/test/java/org/opensearch/node/NodeRoleSettingsTests.java

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public void testClusterManagerAndDataNodeRoles() {
4444
);
4545
}
4646

47+
/**
48+
* Validate search role cannot coexist with any other role on a node.
49+
*/
50+
public void testSearchRoleCannotCoExistWithAnyOtherRole() {
51+
Settings roleSettings = Settings.builder().put(NodeRoleSettings.NODE_ROLES_SETTING.getKey(), "search, test_role").build();
52+
Exception exception = expectThrows(IllegalArgumentException.class, () -> NodeRoleSettings.NODE_ROLES_SETTING.get(roleSettings));
53+
assertThat(exception.getMessage(), containsString("search role cannot be combined with any other role on a node."));
54+
}
55+
4756
/**
4857
* Validate setting master role will result a deprecation message.
4958
* Remove the test after removing MASTER_ROLE.

test/framework/src/main/java/org/opensearch/test/InternalTestCluster.java

+17
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
import static org.opensearch.test.NodeRoles.onlyRole;
167167
import static org.opensearch.test.NodeRoles.onlyRoles;
168168
import static org.opensearch.test.NodeRoles.removeRoles;
169+
import static org.opensearch.test.NodeRoles.searchOnlyNode;
169170
import static org.opensearch.test.OpenSearchTestCase.assertBusy;
170171
import static org.opensearch.test.OpenSearchTestCase.randomBoolean;
171172
import static org.opensearch.test.OpenSearchTestCase.randomFrom;
@@ -2318,6 +2319,22 @@ public List<String> startDataAndWarmNodes(int numNodes, Settings settings) {
23182319
return startNodes(numNodes, Settings.builder().put(onlyRoles(settings, warmAndDataRoles)).build());
23192320
}
23202321

2322+
public List<String> startSearchOnlyNodes(int numNodes) {
2323+
return startSearchOnlyNodes(numNodes, Settings.EMPTY);
2324+
}
2325+
2326+
public List<String> startSearchOnlyNodes(int numNodes, Settings settings) {
2327+
return startNodes(numNodes, Settings.builder().put(searchOnlyNode(settings)).build());
2328+
}
2329+
2330+
public String startSearchOnlyNode() {
2331+
return startSearchOnlyNode(Settings.EMPTY);
2332+
}
2333+
2334+
public String startSearchOnlyNode(Settings settings) {
2335+
return startNode(Settings.builder().put(settings).put(searchOnlyNode(settings)).build());
2336+
}
2337+
23212338
public List<String> startDataOnlyNodes(int numNodes) {
23222339
return startDataOnlyNodes(numNodes, Settings.EMPTY);
23232340
}

test/framework/src/main/java/org/opensearch/test/NodeRoles.java

+15
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,19 @@ public static Settings nonWarmNode(final Settings settings) {
224224
return removeRoles(settings, Collections.singleton(DiscoveryNodeRole.WARM_ROLE));
225225
}
226226

227+
public static Settings searchOnlyNode() {
228+
return searchOnlyNode(Settings.EMPTY);
229+
}
230+
231+
public static Settings searchOnlyNode(final Settings settings) {
232+
return onlyRole(settings, DiscoveryNodeRole.SEARCH_ROLE);
233+
}
234+
235+
public static Settings nonSearchNode() {
236+
return nonSearchNode(Settings.EMPTY);
237+
}
238+
239+
public static Settings nonSearchNode(final Settings settings) {
240+
return removeRoles(settings, Collections.singleton(DiscoveryNodeRole.SEARCH_ROLE));
241+
}
227242
}

0 commit comments

Comments
 (0)