Skip to content

Commit

Permalink
Add some benchmarks for Tarantool cluster with proxy client
Browse files Browse the repository at this point in the history
The new benchmark tries to measure the following things:
 - cost of allocating a new space object for the proxy client
 - cost of writing data to two different spaces (with different mappers)
 - cost of reading data from two different spaces (with diferent mappers)

To get some useful results for memory profiling run this benchmark as
follows:

mvn exec:exec -Pbenchmark -Dbenchmark="ClusterBenchmarkRunner" -DbenchmarkArgs="-prof=jfr"

To analyze these results use the JMC plug-in for Eclipse. You may use
the other profiler types and pass additional arguments to the JMC tool.
  • Loading branch information
akudiyar committed Oct 8, 2023
1 parent 1d82611 commit a0968b8
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 15 deletions.
17 changes: 12 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.35</version>
<scope>test</scope>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.35</version>
<scope>test</scope>
</dependency>
</dependencies>

Expand Down Expand Up @@ -407,12 +407,19 @@
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>org.openjdk.jmh.Main</argument>]
<argument>org.openjdk.jmh.Main</argument>
<argument>${benchmark}</argument>
<argument>${benchmarkArgs}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<skipTests>true</skipTests>
<benchmark>SingleInstanceBenchmarkRunner</benchmark>
<benchmarkArgs></benchmarkArgs>
</properties>
</profile>
<profile>
<id>release</id>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package io.tarantool.driver.benchmark;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

import io.tarantool.driver.api.TarantoolResult;
import io.tarantool.driver.api.conditions.Conditions;
import io.tarantool.driver.api.space.TarantoolSpaceOperations;
import io.tarantool.driver.api.tuple.TarantoolTuple;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.infra.Blackhole;

@Fork(value = 1, jvmArgsAppend = "-Xmx1G")
public class ClusterBenchmarkRunner {
private static final String TEST_SPACE = "test_space";
private static final String TEST_PROFILE = "test__profile";

public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}

@Benchmark
@Measurement(iterations = 10)
@OperationsPerInvocation(2)
public void getSpaceObject(ClusterTarantoolSetup plan, Blackhole bh) {
TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> testSpace =
plan.tarantoolClient.space(TEST_SPACE);
bh.consume(testSpace);

TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> profileSpace =
plan.tarantoolClient.space(TEST_PROFILE);
bh.consume(profileSpace);
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@Measurement(iterations = 10)
@OperationsPerInvocation(2000)
public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) {
// Fill 10000 rows into both spaces
TarantoolTuple tarantoolTuple;
String uuid;
int nextId = 0;
for (int i = 0; i < 1_000; i++) {
uuid = UUID.randomUUID().toString();
nextId = plan.nextTestSpaceId + i;
tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 200_000 + nextId);
futuresHolder.allFutures.add(spaces.testSpace.insert(tarantoolTuple));
tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 50_000 + nextId, 100_000 + i);
futuresHolder.allFutures.add(spaces.profileSpace.insert(tarantoolTuple));
}
nextId++;
plan.nextTestSpaceId = nextId;
plan.nextProfileSpaceId = nextId;
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@Measurement(iterations = 10)
@OperationsPerInvocation(1000)
public void readDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Blackhole bh) {
boolean coin = Math.random() - 0.5 > 0;
String spaceName = coin ? TEST_SPACE : TEST_PROFILE;
long nextId;
for (int i = 0; i < 1_000; i++) {
nextId = Math.round(Math.random() * 10_000) + 1_000_000;
futuresHolder.allFutures.add(
plan.tarantoolClient.callForSingleResult(
"custom_crud_get_one_record", Arrays.asList(spaceName, nextId), List.class)
);
}
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@Measurement(iterations = 10)
@OperationsPerInvocation(1000)
public void readDataUsingSpaceAPI(
ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) {
boolean coin = Math.random() - 0.5 > 0;
TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> space = coin ?
spaces.testSpace : spaces.profileSpace;
String pkFieldName = coin ? "id" : "profile_id";
long nextId;
for (int i = 0; i < 1_000; i++) {
nextId = Math.round(Math.random() * 10_000) + 1_000_000;
futuresHolder.allFutures.add(
space.select(Conditions.indexEquals(pkFieldName, Collections.singletonList(nextId)))
);
}
}

@State(Scope.Thread)
public static class FuturesHolder {
final List<CompletableFuture<?>> allFutures = new ArrayList<>(2_000);

@Setup(Level.Invocation)
public void doSetup() {
allFutures.clear();
}

@TearDown(Level.Invocation)
public void doTeardown() {
allFutures.forEach(CompletableFuture::join);
}
}

@State(Scope.Thread)
public static class Spaces {
TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> testSpace;
TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> profileSpace;

@Setup(Level.Iteration)
public void doSetup(ClusterTarantoolSetup plan) {
testSpace = plan.tarantoolClient.space(TEST_SPACE);
profileSpace = plan.tarantoolClient.space(TEST_PROFILE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.tarantool.driver.benchmark;

import java.time.Duration;

import io.tarantool.driver.api.TarantoolClient;
import io.tarantool.driver.api.TarantoolClientFactory;
import io.tarantool.driver.api.TarantoolResult;
import io.tarantool.driver.api.TarantoolServerAddress;
import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory;
import io.tarantool.driver.api.tuple.TarantoolTuple;
import io.tarantool.driver.api.tuple.TarantoolTupleFactory;
import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory;
import io.tarantool.driver.mappers.MessagePackMapper;

import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.TarantoolCartridgeContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.containers.wait.strategy.Wait;

@State(Scope.Benchmark)
public class ClusterTarantoolSetup {
public Logger logger = LoggerFactory.getLogger(ClusterTarantoolSetup.class);

final MessagePackMapper defaultMapper =
DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper();
final TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(defaultMapper);

final TarantoolCartridgeContainer tarantoolContainer =
new TarantoolCartridgeContainer(
"Dockerfile",
"cartridge-java-test",
"cartridge/instances.yml",
"cartridge/topology.lua")
.withDirectoryBinding("cartridge")
.withLogConsumer(new Slf4jLogConsumer(logger))
.waitingFor(Wait.forLogMessage(".*Listening HTTP on.*", 5))
.withStartupTimeout(Duration.ofMinutes(2));

TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> tarantoolClient;

int nextTestSpaceId;
int nextProfileSpaceId;

private void initClient() {
tarantoolClient = TarantoolClientFactory.createClient()
.withAddresses(
new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3301)),
new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3302)),
new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3303))
)
.withCredentials(tarantoolContainer.getUsername(), tarantoolContainer.getPassword())
.withConnections(10)
.withEventLoopThreadsNumber(10)
.withRequestTimeout(10000)
.withProxyMethodMapping()
.build();
}

@Setup(Level.Trial)
public void doSetup() {
System.out.println("Do Setup");
if (!tarantoolContainer.isRunning()) {
tarantoolContainer.start();
}
initClient();
}

@TearDown(Level.Trial)
public void doTearDown() throws Exception {
System.out.println("Do TearDown");
tarantoolClient.close();
tarantoolContainer.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;

public class BenchmarkRunner {
public class SingleInstanceBenchmarkRunner {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
Expand All @@ -29,7 +29,7 @@ public static void main(String[] args) throws Exception {
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void acceptingDiffTypes(TarantoolSetup plan, Blackhole bh) {
public void acceptingDiffTypes(SingleInstanceTarantoolSetup plan, Blackhole bh) {
List<?> result = plan.tarantoolClient.call(
"return_arrays_with_different_types"
).join();
Expand Down Expand Up @@ -66,7 +66,7 @@ public void acceptingDiffTypes(TarantoolSetup plan, Blackhole bh) {
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void acceptingDiffTypesAsTuplesAndUnpackIt(TarantoolSetup plan, Blackhole bh) {
public void acceptingDiffTypesAsTuplesAndUnpackIt(SingleInstanceTarantoolSetup plan, Blackhole bh) {
TarantoolResult<TarantoolTuple> tuples = plan.tarantoolClient.call(
"return_arrays_with_different_types",
Collections.emptyList(),
Expand Down Expand Up @@ -104,7 +104,7 @@ public void acceptingDiffTypesAsTuplesAndUnpackIt(TarantoolSetup plan, Blackhole
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(TarantoolSetup plan, Blackhole bh) {
public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(SingleInstanceTarantoolSetup plan, Blackhole bh) {
TarantoolResult<TarantoolTuple> tuples = plan.tarantoolClient.call(
"return_arrays_with_different_types",
Collections.emptyList(),
Expand Down Expand Up @@ -142,7 +142,7 @@ public void acceptingDiffTypesAsTuplesAndUnpackItWithTargetType(TarantoolSetup p
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void passingArrayOfArraysWithDiffTypes(TarantoolSetup plan, Blackhole bh) {
public void passingArrayOfArraysWithDiffTypes(SingleInstanceTarantoolSetup plan, Blackhole bh) {
bh.consume(plan.tarantoolClient.call(
"empty_function", plan.arraysWithDiffElements).join());
}
Expand All @@ -151,7 +151,7 @@ public void passingArrayOfArraysWithDiffTypes(TarantoolSetup plan, Blackhole bh)
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void passingArrayOfArraysWithNestedArrays(TarantoolSetup plan, Blackhole bh) {
public void passingArrayOfArraysWithNestedArrays(SingleInstanceTarantoolSetup plan, Blackhole bh) {
bh.consume(plan.tarantoolClient.call(
"empty_function", plan.arraysWithNestedArrays).join());
}
Expand All @@ -160,15 +160,15 @@ public void passingArrayOfArraysWithNestedArrays(TarantoolSetup plan, Blackhole
@Fork(1)
@BenchmarkMode(Mode.Throughput)
@OperationsPerInvocation(1000)
public void passingArrayOfArraysWithNestedMaps(TarantoolSetup plan, Blackhole bh) {
public void passingArrayOfArraysWithNestedMaps(SingleInstanceTarantoolSetup plan, Blackhole bh) {
bh.consume(plan.tarantoolClient.call(
"empty_function", plan.arraysWithNestedMaps).join());
}

@Benchmark
@Fork(1)
@BenchmarkMode(Mode.Throughput)
public void spaceCall(TarantoolSetup plan, Blackhole bh) {
public void spaceCall(SingleInstanceTarantoolSetup plan, Blackhole bh) {
bh.consume(plan.retryingTarantoolClient.space(
"test_space"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
import java.util.function.Supplier;

@State(Scope.Benchmark)
public class TarantoolSetup {
public Logger log = LoggerFactory.getLogger(TarantoolSetup.class);
public class SingleInstanceTarantoolSetup {
public Logger log = LoggerFactory.getLogger(SingleInstanceTarantoolSetup.class);

public TarantoolContainer tarantoolContainer = new TarantoolContainer()
.withScriptFileName("org/testcontainers/containers/benchmark.lua")
Expand Down

0 comments on commit a0968b8

Please sign in to comment.