use of org.opensearch.node.ResponseCollectorService in project OpenSearch by opensearch-project.
the class OperationRoutingTests method testAdaptiveReplicaSelection.
public void testAdaptiveReplicaSelection() throws Exception {
final int numIndices = 1;
final int numShards = 1;
final int numReplicas = 2;
final String[] indexNames = new String[numIndices];
for (int i = 0; i < numIndices; i++) {
indexNames[i] = "test" + i;
}
ClusterState state = ClusterStateCreationUtils.stateWithAssignedPrimariesAndReplicas(indexNames, numShards, numReplicas);
OperationRouting opRouting = new OperationRouting(Settings.EMPTY, new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS));
opRouting.setUseAdaptiveReplicaSelection(true);
List<ShardRouting> searchedShards = new ArrayList<>(numShards);
Set<String> selectedNodes = new HashSet<>(numShards);
TestThreadPool threadPool = new TestThreadPool("testThatOnlyNodesSupportNodeIds");
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
ResponseCollectorService collector = new ResponseCollectorService(clusterService);
Map<String, Long> outstandingRequests = new HashMap<>();
GroupShardsIterator<ShardIterator> groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
assertThat("One group per index shard", groupIterator.size(), equalTo(numIndices * numShards));
// Test that the shards use a round-robin pattern when there are no stats
assertThat(groupIterator.get(0).size(), equalTo(numReplicas + 1));
ShardRouting firstChoice = groupIterator.get(0).nextOrNull();
assertNotNull(firstChoice);
searchedShards.add(firstChoice);
selectedNodes.add(firstChoice.currentNodeId());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
assertThat(groupIterator.size(), equalTo(numIndices * numShards));
ShardRouting secondChoice = groupIterator.get(0).nextOrNull();
assertNotNull(secondChoice);
searchedShards.add(secondChoice);
selectedNodes.add(secondChoice.currentNodeId());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
assertThat(groupIterator.size(), equalTo(numIndices * numShards));
ShardRouting thirdChoice = groupIterator.get(0).nextOrNull();
assertNotNull(thirdChoice);
searchedShards.add(thirdChoice);
selectedNodes.add(thirdChoice.currentNodeId());
// All three shards should have been separate, because there are no stats yet so they're all ranked equally.
assertThat(searchedShards.size(), equalTo(3));
// Now let's start adding node metrics, since that will affect which node is chosen
collector.addNodeStatistics("node_0", 2, TimeValue.timeValueMillis(200).nanos(), TimeValue.timeValueMillis(150).nanos());
collector.addNodeStatistics("node_1", 1, TimeValue.timeValueMillis(100).nanos(), TimeValue.timeValueMillis(50).nanos());
collector.addNodeStatistics("node_2", 1, TimeValue.timeValueMillis(200).nanos(), TimeValue.timeValueMillis(200).nanos());
outstandingRequests.put("node_0", 1L);
outstandingRequests.put("node_1", 1L);
outstandingRequests.put("node_2", 1L);
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
ShardRouting shardChoice = groupIterator.get(0).nextOrNull();
// node 1 should be the lowest ranked node to start
assertThat(shardChoice.currentNodeId(), equalTo("node_1"));
// node 1 starts getting more loaded...
collector.addNodeStatistics("node_1", 2, TimeValue.timeValueMillis(200).nanos(), TimeValue.timeValueMillis(150).nanos());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
shardChoice = groupIterator.get(0).nextOrNull();
assertThat(shardChoice.currentNodeId(), equalTo("node_1"));
// and more loaded...
collector.addNodeStatistics("node_1", 3, TimeValue.timeValueMillis(250).nanos(), TimeValue.timeValueMillis(200).nanos());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
shardChoice = groupIterator.get(0).nextOrNull();
assertThat(shardChoice.currentNodeId(), equalTo("node_1"));
// and even more
collector.addNodeStatistics("node_1", 4, TimeValue.timeValueMillis(300).nanos(), TimeValue.timeValueMillis(250).nanos());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
shardChoice = groupIterator.get(0).nextOrNull();
// finally, node 2 is chosen instead
assertThat(shardChoice.currentNodeId(), equalTo("node_2"));
IOUtils.close(clusterService);
terminate(threadPool);
}
use of org.opensearch.node.ResponseCollectorService in project OpenSearch by opensearch-project.
the class OperationRoutingTests method testAdaptiveReplicaSelectionWithZoneAwarenessIgnored.
// Regression test to ignore awareness attributes. This test creates shards in different zones and simulates stress
// on nodes in one zone to test if Adapative Replica Selection smartly routes the request to a node in different zone
// by ignoring the zone awareness attributes.
public void testAdaptiveReplicaSelectionWithZoneAwarenessIgnored() throws Exception {
final int numIndices = 2;
final int numShards = 1;
final int numReplicas = 1;
final String[] indexNames = new String[numIndices];
for (int i = 0; i < numIndices; i++) {
indexNames[i] = "test" + i;
}
DiscoveryNode[] allNodes = setupNodes();
ClusterState state = ClusterStateCreationUtils.state(allNodes[0], allNodes[3], allNodes);
// Updates cluster state by assigning shard copies on nodes
state = updateStatetoTestARS(indexNames, numShards, numReplicas, allNodes, state);
Settings awarenessSetting = Settings.builder().put("cluster.routing.allocation.awareness.attributes", "zone").build();
TestThreadPool threadPool = new TestThreadPool("testThatOnlyNodesSupport");
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
OperationRouting opRouting = new OperationRouting(awarenessSetting, new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS));
opRouting.setUseAdaptiveReplicaSelection(true);
assertTrue(opRouting.ignoreAwarenessAttributes());
List<ShardRouting> searchedShards = new ArrayList<>(numShards);
Set<String> selectedNodes = new HashSet<>(numShards);
ResponseCollectorService collector = new ResponseCollectorService(clusterService);
Map<String, Long> outstandingRequests = new HashMap<>();
GroupShardsIterator<ShardIterator> groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
assertThat("One group per index shard", groupIterator.size(), equalTo(numIndices * numShards));
// Test that the shards use a round-robin pattern when there are no stats
assertThat(groupIterator.size(), equalTo(numIndices * numShards));
assertThat(groupIterator.get(0).size(), equalTo(numReplicas + 1));
ShardRouting firstChoice = groupIterator.get(0).nextOrNull();
assertNotNull(firstChoice);
searchedShards.add(firstChoice);
selectedNodes.add(firstChoice.currentNodeId());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
assertThat(groupIterator.size(), equalTo(numIndices * numShards));
assertThat(groupIterator.get(0).size(), equalTo(numReplicas + 1));
ShardRouting secondChoice = groupIterator.get(0).nextOrNull();
assertNotNull(secondChoice);
searchedShards.add(secondChoice);
selectedNodes.add(secondChoice.currentNodeId());
// All the shards should be ranked equally since there are no stats yet
assertTrue(selectedNodes.contains("node_b2"));
// Since the primary shards are divided randomly between node_a0 and node_a1
assertTrue(selectedNodes.contains("node_a0") || selectedNodes.contains("node_a1"));
// Now let's start adding node metrics, since that will affect which node is chosen. Adding more load to node_b2
collector.addNodeStatistics("node_a0", 1, TimeValue.timeValueMillis(50).nanos(), TimeValue.timeValueMillis(50).nanos());
collector.addNodeStatistics("node_a1", 20, TimeValue.timeValueMillis(100).nanos(), TimeValue.timeValueMillis(150).nanos());
collector.addNodeStatistics("node_b2", 40, TimeValue.timeValueMillis(250).nanos(), TimeValue.timeValueMillis(250).nanos());
outstandingRequests.put("node_a0", 1L);
outstandingRequests.put("node_a1", 1L);
outstandingRequests.put("node_b2", 1L);
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
// node_a0 or node_a1 should be the lowest ranked node to start
groupIterator.forEach(shardRoutings -> assertThat(shardRoutings.nextOrNull().currentNodeId(), containsString("node_a")));
// Adding more load to node_a0
collector.addNodeStatistics("node_a0", 10, TimeValue.timeValueMillis(200).nanos(), TimeValue.timeValueMillis(150).nanos());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
// Adding more load to node_a0 and node_a1 from zone-a
collector.addNodeStatistics("node_a1", 100, TimeValue.timeValueMillis(300).nanos(), TimeValue.timeValueMillis(250).nanos());
collector.addNodeStatistics("node_a0", 100, TimeValue.timeValueMillis(300).nanos(), TimeValue.timeValueMillis(250).nanos());
groupIterator = opRouting.searchShards(state, indexNames, null, null, collector, outstandingRequests);
// ARS should pick node_b2 from zone-b since both node_a0 and node_a1 are overloaded
groupIterator.forEach(shardRoutings -> assertThat(shardRoutings.nextOrNull().currentNodeId(), containsString("node_b")));
IOUtils.close(clusterService);
terminate(threadPool);
}
Aggregations