You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by nr...@apache.org on 2018/03/26 21:57:57 UTC
[geode] branch develop updated: GEODE-4808: Add performance tests
for rebalance simulation (#1667)
This is an automated email from the ASF dual-hosted git repository.
nreich pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 6d729d3 GEODE-4808: Add performance tests for rebalance simulation (#1667)
6d729d3 is described below
commit 6d729d3bb7d83d2d335a618d14ead89d4bc5f1ab
Author: Nick Reich <nr...@pivotal.io>
AuthorDate: Mon Mar 26 14:57:54 2018 -0700
GEODE-4808: Add performance tests for rebalance simulation (#1667)
---
.../RebalanceGrowingClusterBenchmark.java | 71 ++++++++
.../rebalance/RebalanceModelBuilder.java | 188 +++++++++++++++++++++
.../RebalanceOnAddingMemberBenchmark.java | 73 ++++++++
.../rebalance/RebalanceRegionBenchmark.java | 73 ++++++++
4 files changed, 405 insertions(+)
diff --git a/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceGrowingClusterBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceGrowingClusterBenchmark.java
new file mode 100644
index 0000000..5855c65
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceGrowingClusterBenchmark.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF 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.apache.geode.cache.partitioned.rebalance;
+
+import java.net.UnknownHostException;
+import java.util.concurrent.TimeUnit;
+
+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.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.apache.geode.internal.cache.partitioned.rebalance.MoveBuckets;
+import org.apache.geode.internal.cache.partitioned.rebalance.RebalanceDirector;
+import org.apache.geode.internal.cache.partitioned.rebalance.model.PartitionedRegionLoadModel;
+
+/**
+ * This test simulates an existing partitioned region with evenly distributed numbers of buckets,
+ * all of which are exactly the same size and with no replicate copies. The number of members is
+ * then doubled and the region rebalanced across the new members. This represents a best-case
+ * scenario for rebalancing a cluster after greatly increasing the number of members.
+ */
+@State(Scope.Thread)
+@Fork(1)
+public class RebalanceGrowingClusterBenchmark {
+
+ @Param({"1", "2", "4", "8", "16", "32"})
+ public int startingMembers;
+
+ @Benchmark
+ @Measurement(time = 5, iterations = 10)
+ @Warmup(iterations = 5)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.MILLISECONDS)
+ public int doubleMembersAndRebalancedRegion() throws UnknownHostException {
+ int totalBuckets = startingMembers * 31;
+ RebalanceModelBuilder modelBuilder = new RebalanceModelBuilder(startingMembers, totalBuckets);
+ PartitionedRegionLoadModel model = modelBuilder.withNewMembers(startingMembers).createModel();
+ return doMoves(new MoveBuckets(), model);
+ }
+
+ private int doMoves(RebalanceDirector director, PartitionedRegionLoadModel model) {
+ int moveCount = 0;
+
+ model.initialize();
+ director.initialize(model);
+ while (director.nextStep()) {
+ moveCount++;
+ }
+
+ return moveCount;
+ }
+}
diff --git a/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceModelBuilder.java b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceModelBuilder.java
new file mode 100644
index 0000000..95d731a
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceModelBuilder.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF 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.apache.geode.cache.partitioned.rebalance;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.geode.DataSerializer;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.cache.partitioned.OfflineMemberDetails;
+import org.apache.geode.internal.cache.partitioned.PRLoad;
+import org.apache.geode.internal.cache.partitioned.PartitionMemberInfoImpl;
+import org.apache.geode.internal.cache.partitioned.rebalance.SimulatedBucketOperator;
+import org.apache.geode.internal.cache.partitioned.rebalance.model.AddressComparor;
+import org.apache.geode.internal.cache.partitioned.rebalance.model.PartitionedRegionLoadModel;
+import org.apache.geode.internal.cache.persistence.PersistentMemberID;
+
+class RebalanceModelBuilder {
+ private static final int DEFAULT_MEAN_BUCKET_SIZE = 100;
+
+ private final Random random = new Random();
+ private int members;
+ private int buckets;
+ private int newMembers;
+ private int bucketSizeDeviation;
+
+ RebalanceModelBuilder(int members, int buckets) {
+ this.members = members;
+ this.buckets = buckets;
+ }
+
+ RebalanceModelBuilder withNewMembers(int newMembers) {
+ this.newMembers = newMembers;
+ return this;
+ }
+
+ RebalanceModelBuilder withBucketSizeStandardDeviation(int deviation) {
+ this.bucketSizeDeviation = deviation;
+ return this;
+ }
+
+ PartitionedRegionLoadModel createModel() throws UnknownHostException {
+ SimulatedBucketOperator bucketOperator = new SimulatedBucketOperator();
+ PartitionedRegionLoadModel model = new PartitionedRegionLoadModel(bucketOperator, 0, buckets,
+ comparor, Collections.emptySet(), null);
+ double bucketsPerMember = (double) buckets / members;
+ int bucketOffset = 0;
+ List<PartitionMemberInfoImpl> members = new ArrayList<>();
+
+ for (int memberId = 0; memberId < this.members; memberId++) {
+ int bucketsOnMember = getBucketsOnMember(bucketsPerMember, memberId);
+ long[] loads = new long[this.buckets];
+ long[] primaryLoads = new long[this.buckets];
+ for (int bucketId = bucketOffset; bucketId < bucketOffset + bucketsOnMember; bucketId++) {
+ loads[bucketId] = getBucketSize(memberId);
+ primaryLoads[bucketId] = 1;
+ }
+
+ InternalDistributedMember member =
+ new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), memberId);
+ PartitionMemberInfoImpl memberInfo =
+ buildDetails(member, 500, Integer.MAX_VALUE, loads, primaryLoads);
+ members.add(memberInfo);
+
+ bucketOffset += bucketsOnMember;
+ }
+
+ members.addAll(getNewMembers());
+ model.addRegion("a", members, new FakeOfflineDetails(), true);
+ return model;
+ }
+
+ private int getBucketsOnMember(double bucketsPerMember, double memberId) {
+ if (memberId / this.members < (bucketsPerMember - (int) bucketsPerMember)) {
+ return (int) Math.ceil(bucketsPerMember);
+ } else {
+ return (int) Math.floor(bucketsPerMember);
+ }
+ }
+
+ private int getBucketSize(int memberId) {
+ int loadDeviation = (int) (random.nextGaussian() * bucketSizeDeviation);
+
+ if (memberId % 2 == 0) {
+ return DEFAULT_MEAN_BUCKET_SIZE + Math.abs(loadDeviation);
+ } else {
+ return DEFAULT_MEAN_BUCKET_SIZE - Math.abs(loadDeviation);
+ }
+ }
+
+ private List<PartitionMemberInfoImpl> getNewMembers() throws UnknownHostException {
+ List<PartitionMemberInfoImpl> members = new ArrayList<>();
+ for (int i = 0; i < newMembers; i++) {
+ InternalDistributedMember newMember =
+ new InternalDistributedMember(InetAddress.getByName("127.0.0.1"), this.members + i);
+ PartitionMemberInfoImpl newMemberInfo =
+ buildDetails(newMember, 500, Integer.MAX_VALUE, new long[buckets], new long[buckets]);
+ members.add(newMemberInfo);
+ }
+ return members;
+ }
+
+
+ private PartitionMemberInfoImpl buildDetails(InternalDistributedMember id, float weight,
+ long localMaxMemory, long[] loads, long[] primaryLoads) {
+ PRLoad prLoad = new PRLoad(loads.length, weight);
+ int size = 0;
+ int primaryCount = 0;
+ int bucketCount = 0;
+ long[] bucketSizes = new long[loads.length];
+ for (int bucketId = 0; bucketId < loads.length; bucketId++) {
+ prLoad.addBucket(bucketId, loads[bucketId], primaryLoads[bucketId]);
+ bucketSizes[bucketId] = loads[bucketId];
+ size += bucketSizes[bucketId];
+ if (loads[bucketId] != 0) {
+ bucketCount++;
+ }
+ if (primaryLoads[bucketId] != 0) {
+ primaryCount++;
+ }
+ }
+ return new PartitionMemberInfoImpl(id, localMaxMemory, size, bucketCount, primaryCount, prLoad,
+ bucketSizes);
+ }
+
+ private static final AddressComparor comparor = new AddressComparor() {
+ @Override
+ public boolean enforceUniqueZones() {
+ return false;
+ }
+
+ @Override
+ public boolean areSameZone(InternalDistributedMember member1,
+ InternalDistributedMember member2) {
+ return false;
+ }
+ };
+
+ private static class FakeOfflineDetails implements OfflineMemberDetails {
+
+ private Set<PersistentMemberID> offlineMembers;
+
+ FakeOfflineDetails() {
+ this(Collections.emptySet());
+ }
+
+ FakeOfflineDetails(Set<PersistentMemberID> offlineMembers) {
+ this.offlineMembers = offlineMembers;
+ }
+
+ @Override
+ public Set<PersistentMemberID> getOfflineMembers(int bucketId) {
+ return this.offlineMembers;
+ }
+
+ @Override
+ public void fromData(DataInput in) throws IOException, ClassNotFoundException {
+ offlineMembers = DataSerializer.readObject(in);
+ }
+
+ @Override
+ public void toData(DataOutput out) throws IOException {
+ DataSerializer.writeObject(offlineMembers, out);
+
+ }
+
+ }
+}
diff --git a/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceOnAddingMemberBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceOnAddingMemberBenchmark.java
new file mode 100644
index 0000000..7fae3d4
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceOnAddingMemberBenchmark.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF 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.apache.geode.cache.partitioned.rebalance;
+
+import java.net.UnknownHostException;
+import java.util.concurrent.TimeUnit;
+
+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.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.apache.geode.internal.cache.partitioned.rebalance.MoveBuckets;
+import org.apache.geode.internal.cache.partitioned.rebalance.RebalanceDirector;
+import org.apache.geode.internal.cache.partitioned.rebalance.model.PartitionedRegionLoadModel;
+
+/**
+ * This test simulates an existing partitioned region with evenly distributed numbers of buckets,
+ * all of which are exactly the same size and with no replicate copies. A single new member is added
+ * to the cluster and the region is then rebalanced. This represents a best-case scenario for
+ * rebalancing a cluster after the addition of a member.
+ */
+@State(Scope.Thread)
+@Fork(1)
+public class RebalanceOnAddingMemberBenchmark {
+
+ @Param({"4", "8", "16", "32", "64", "128"})
+ public int startingMembers;
+
+ @Param({"100", "200", "400", "800", "1600", "3200"})
+ public int totalBuckets;
+
+ @Benchmark
+ @Measurement(time = 5, iterations = 10)
+ @Warmup(iterations = 5)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.MILLISECONDS)
+ public int addNewMemberToBalancedRegion() throws UnknownHostException {
+ RebalanceModelBuilder modelBuilder = new RebalanceModelBuilder(startingMembers, totalBuckets);
+ PartitionedRegionLoadModel model = modelBuilder.withNewMembers(1).createModel();
+ return doMoves(new MoveBuckets(), model);
+ }
+
+ private int doMoves(RebalanceDirector director, PartitionedRegionLoadModel model) {
+ int moveCount = 0;
+
+ model.initialize();
+ director.initialize(model);
+ while (director.nextStep()) {
+ moveCount++;
+ }
+
+ return moveCount;
+ }
+}
diff --git a/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceRegionBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceRegionBenchmark.java
new file mode 100644
index 0000000..d9d2be7
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/cache/partitioned/rebalance/RebalanceRegionBenchmark.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF 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.apache.geode.cache.partitioned.rebalance;
+
+import java.net.UnknownHostException;
+import java.util.concurrent.TimeUnit;
+
+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.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.apache.geode.internal.cache.partitioned.rebalance.MoveBuckets;
+import org.apache.geode.internal.cache.partitioned.rebalance.RebalanceDirector;
+import org.apache.geode.internal.cache.partitioned.rebalance.model.PartitionedRegionLoadModel;
+
+/**
+ * This test simulates a worst case scenario for rebalancing a region. Each bucket is of a
+ * different size, randomly determined, but defined by a Gaussian distribution. All buckets
+ * on a member are either larger or smaller than the average bucket size, which leads to a
+ * maximal number of bucket moves being required.
+ */
+@State(Scope.Thread)
+@Fork(1)
+public class RebalanceRegionBenchmark {
+ private static final int STARTING_MEMBERS = 32;
+ private static final int TOTAL_BUCKETS = 800;
+
+ @Param({"0", "5", "10", "15", "20"})
+ public int deviation;
+
+ @Benchmark
+ @Measurement(time = 5, iterations = 10)
+ @Warmup(iterations = 5)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.MILLISECONDS)
+ public int rebalance() throws UnknownHostException {
+ RebalanceModelBuilder modelBuilder = new RebalanceModelBuilder(STARTING_MEMBERS, TOTAL_BUCKETS);
+ PartitionedRegionLoadModel model =
+ modelBuilder.withBucketSizeStandardDeviation(deviation).createModel();
+ return doMoves(new MoveBuckets(), model);
+ }
+
+ private int doMoves(RebalanceDirector director, PartitionedRegionLoadModel model) {
+ int moveCount = 0;
+
+ model.initialize();
+ director.initialize(model);
+ while (director.nextStep()) {
+ moveCount++;
+ }
+
+ return moveCount;
+ }
+}
--
To stop receiving notification emails like this one, please contact
nreich@apache.org.