Search in sources :

Example 1 with ResponseCollectorService

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);
}
Also used : ClusterState(org.opensearch.cluster.ClusterState) ClusterSettings(org.opensearch.common.settings.ClusterSettings) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ResponseCollectorService(org.opensearch.node.ResponseCollectorService) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) HasToString.hasToString(org.hamcrest.object.HasToString.hasToString) TestThreadPool(org.opensearch.threadpool.TestThreadPool) ClusterService(org.opensearch.cluster.service.ClusterService) HashSet(java.util.HashSet)

Example 2 with ResponseCollectorService

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);
}
Also used : ClusterState(org.opensearch.cluster.ClusterState) DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) ClusterSettings(org.opensearch.common.settings.ClusterSettings) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ResponseCollectorService(org.opensearch.node.ResponseCollectorService) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) HasToString.hasToString(org.hamcrest.object.HasToString.hasToString) TestThreadPool(org.opensearch.threadpool.TestThreadPool) ClusterService(org.opensearch.cluster.service.ClusterService) ClusterSettings(org.opensearch.common.settings.ClusterSettings) Settings(org.opensearch.common.settings.Settings) HashSet(java.util.HashSet)

Aggregations

ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)2 HasToString.hasToString (org.hamcrest.object.HasToString.hasToString)2 ClusterState (org.opensearch.cluster.ClusterState)2 ClusterService (org.opensearch.cluster.service.ClusterService)2 ClusterSettings (org.opensearch.common.settings.ClusterSettings)2 ResponseCollectorService (org.opensearch.node.ResponseCollectorService)2 TestThreadPool (org.opensearch.threadpool.TestThreadPool)2 DiscoveryNode (org.opensearch.cluster.node.DiscoveryNode)1 Settings (org.opensearch.common.settings.Settings)1