|
@@ -0,0 +1,170 @@
|
|
|
+/*
|
|
|
+ * Licensed to Elasticsearch under one or more contributor
|
|
|
+ * license agreements. See the NOTICE file distributed with
|
|
|
+ * this work for additional information regarding copyright
|
|
|
+ * ownership. Elasticsearch licenses this file to you under
|
|
|
+ * the Apache License, Version 2.0 (the "License"); you may
|
|
|
+ * not use this file except in compliance with the License.
|
|
|
+ * You may obtain a copy of the License at
|
|
|
+ *
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+ *
|
|
|
+ * Unless required by applicable law or agreed to in writing,
|
|
|
+ * software distributed under the License is distributed on an
|
|
|
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
+ * KIND, either express or implied. See the License for the
|
|
|
+ * specific language governing permissions and limitations
|
|
|
+ * under the License.
|
|
|
+ */
|
|
|
+package org.elasticsearch.benchmark.routing.allocation;
|
|
|
+
|
|
|
+import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.cluster.ClusterName;
|
|
|
+import org.elasticsearch.cluster.ClusterState;
|
|
|
+import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|
|
+import org.elasticsearch.cluster.metadata.MetaData;
|
|
|
+import org.elasticsearch.cluster.node.DiscoveryNodes;
|
|
|
+import org.elasticsearch.cluster.routing.RoutingTable;
|
|
|
+import org.elasticsearch.cluster.routing.ShardRoutingState;
|
|
|
+import org.elasticsearch.cluster.routing.allocation.AllocationService;
|
|
|
+import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
+import org.openjdk.jmh.annotations.Benchmark;
|
|
|
+import org.openjdk.jmh.annotations.BenchmarkMode;
|
|
|
+import org.openjdk.jmh.annotations.Fork;
|
|
|
+import org.openjdk.jmh.annotations.Measurement;
|
|
|
+import org.openjdk.jmh.annotations.Mode;
|
|
|
+import org.openjdk.jmh.annotations.OutputTimeUnit;
|
|
|
+import org.openjdk.jmh.annotations.Param;
|
|
|
+import org.openjdk.jmh.annotations.Scope;
|
|
|
+import org.openjdk.jmh.annotations.Setup;
|
|
|
+import org.openjdk.jmh.annotations.State;
|
|
|
+import org.openjdk.jmh.annotations.Warmup;
|
|
|
+
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+@Fork(3)
|
|
|
+@Warmup(iterations = 10)
|
|
|
+@Measurement(iterations = 10)
|
|
|
+@BenchmarkMode(Mode.AverageTime)
|
|
|
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
|
|
+@State(Scope.Benchmark)
|
|
|
+@SuppressWarnings("unused") //invoked by benchmarking framework
|
|
|
+public class AllocationBenchmark {
|
|
|
+ // Do NOT make any field final (even if it is not annotated with @Param)! See also
|
|
|
+ // http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_10_ConstantFold.java
|
|
|
+
|
|
|
+ // we cannot use individual @Params as some will lead to invalid combinations which do not let the benchmark terminate. JMH offers no
|
|
|
+ // support to constrain the combinations of benchmark parameters and we do not want to rely on OptionsBuilder as each benchmark would
|
|
|
+ // need its own main method and we cannot execute more than one class with a main method per JAR.
|
|
|
+ @Param({
|
|
|
+ // indices, shards, replicas, nodes
|
|
|
+ " 10, 1, 0, 1",
|
|
|
+ " 10, 3, 0, 1",
|
|
|
+ " 10, 10, 0, 1",
|
|
|
+ " 100, 1, 0, 1",
|
|
|
+ " 100, 3, 0, 1",
|
|
|
+ " 100, 10, 0, 1",
|
|
|
+
|
|
|
+ " 10, 1, 0, 10",
|
|
|
+ " 10, 3, 0, 10",
|
|
|
+ " 10, 10, 0, 10",
|
|
|
+ " 100, 1, 0, 10",
|
|
|
+ " 100, 3, 0, 10",
|
|
|
+ " 100, 10, 0, 10",
|
|
|
+
|
|
|
+ " 10, 1, 1, 10",
|
|
|
+ " 10, 3, 1, 10",
|
|
|
+ " 10, 10, 1, 10",
|
|
|
+ " 100, 1, 1, 10",
|
|
|
+ " 100, 3, 1, 10",
|
|
|
+ " 100, 10, 1, 10",
|
|
|
+
|
|
|
+ " 10, 1, 2, 10",
|
|
|
+ " 10, 3, 2, 10",
|
|
|
+ " 10, 10, 2, 10",
|
|
|
+ " 100, 1, 2, 10",
|
|
|
+ " 100, 3, 2, 10",
|
|
|
+ " 100, 10, 2, 10",
|
|
|
+
|
|
|
+ " 10, 1, 0, 50",
|
|
|
+ " 10, 3, 0, 50",
|
|
|
+ " 10, 10, 0, 50",
|
|
|
+ " 100, 1, 0, 50",
|
|
|
+ " 100, 3, 0, 50",
|
|
|
+ " 100, 10, 0, 50",
|
|
|
+
|
|
|
+ " 10, 1, 1, 50",
|
|
|
+ " 10, 3, 1, 50",
|
|
|
+ " 10, 10, 1, 50",
|
|
|
+ " 100, 1, 1, 50",
|
|
|
+ " 100, 3, 1, 50",
|
|
|
+ " 100, 10, 1, 50",
|
|
|
+
|
|
|
+ " 10, 1, 2, 50",
|
|
|
+ " 10, 3, 2, 50",
|
|
|
+ " 10, 10, 2, 50",
|
|
|
+ " 100, 1, 2, 50",
|
|
|
+ " 100, 3, 2, 50",
|
|
|
+ " 100, 10, 2, 50"
|
|
|
+ })
|
|
|
+ public String indicesShardsReplicasNodes = "10,1,0,1";
|
|
|
+
|
|
|
+ public int numTags = 2;
|
|
|
+
|
|
|
+ private AllocationService strategy;
|
|
|
+ private ClusterState initialClusterState;
|
|
|
+
|
|
|
+ @Setup
|
|
|
+ public void setUp() throws Exception {
|
|
|
+ final String[] params = indicesShardsReplicasNodes.split(",");
|
|
|
+
|
|
|
+ int numIndices = toInt(params[0]);
|
|
|
+ int numShards = toInt(params[1]);
|
|
|
+ int numReplicas = toInt(params[2]);
|
|
|
+ int numNodes = toInt(params[3]);
|
|
|
+
|
|
|
+ strategy = Allocators.createAllocationService(Settings.builder()
|
|
|
+ .put("cluster.routing.allocation.awareness.attributes", "tag")
|
|
|
+ .build());
|
|
|
+
|
|
|
+ MetaData.Builder mb = MetaData.builder();
|
|
|
+ for (int i = 1; i <= numIndices; i++) {
|
|
|
+ mb.put(IndexMetaData.builder("test_" + i)
|
|
|
+ .settings(Settings.builder().put("index.version.created", Version.CURRENT))
|
|
|
+ .numberOfShards(numShards)
|
|
|
+ .numberOfReplicas(numReplicas)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ MetaData metaData = mb.build();
|
|
|
+ RoutingTable.Builder rb = RoutingTable.builder();
|
|
|
+ for (int i = 1; i <= numIndices; i++) {
|
|
|
+ rb.addAsNew(metaData.index("test_" + i));
|
|
|
+ }
|
|
|
+ RoutingTable routingTable = rb.build();
|
|
|
+ DiscoveryNodes.Builder nb = DiscoveryNodes.builder();
|
|
|
+ for (int i = 1; i <= numNodes; i++) {
|
|
|
+ nb.put(Allocators.newNode("node" + i, Collections.singletonMap("tag", "tag_" + (i % numTags))));
|
|
|
+ }
|
|
|
+ initialClusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).routingTable(routingTable).nodes
|
|
|
+ (nb).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private int toInt(String v) {
|
|
|
+ return Integer.valueOf(v.trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Benchmark
|
|
|
+ public ClusterState measureAllocation() {
|
|
|
+ ClusterState clusterState = initialClusterState;
|
|
|
+ while (clusterState.getRoutingNodes().hasUnassignedShards()) {
|
|
|
+ RoutingAllocation.Result result = strategy.applyStartedShards(clusterState, clusterState.getRoutingNodes()
|
|
|
+ .shardsWithState(ShardRoutingState.INITIALIZING));
|
|
|
+ clusterState = ClusterState.builder(clusterState).routingResult(result).build();
|
|
|
+ result = strategy.reroute(clusterState, "reroute");
|
|
|
+ clusterState = ClusterState.builder(clusterState).routingResult(result).build();
|
|
|
+ }
|
|
|
+ return clusterState;
|
|
|
+ }
|
|
|
+}
|