From 0248c04a6eb9899652c3c5794c0087770fa6bafd Mon Sep 17 00:00:00 2001 From: Alexey Kuzin Date: Sat, 18 Nov 2023 22:06:32 +0100 Subject: [PATCH] Add benchmark for inserting a tuple using call API Additionally - add custom profile for running the benchmark - fix read benchmarks being run without data in the cluster --- CHANGELOG.md | 6 + profile.jfc | 809 ++++++++++++++++++ .../benchmark/ClusterBenchmarkRunner.java | 93 +- .../benchmark/ClusterTarantoolSetup.java | 5 +- .../cartridge/app/roles/api_router.lua | 5 + .../containers/cluster_benchmark.lua | 10 + 6 files changed, 900 insertions(+), 28 deletions(-) create mode 100644 profile.jfc create mode 100644 src/test/resources/org/testcontainers/containers/cluster_benchmark.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index e187feff..287021df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,17 @@ # Changelog ## [Unreleased] + +### Bugfixes + +- Significantly reduce memory allocation overhead and excessive GC pressure ([#401](https://github.com/tarantool/cartridge-java/issues/401)) + ### Internal and API changes - Bump org.testcontainers:junit-jupiter version to 1.19.3 ([#442](https://github.com/tarantool/cartridge-java/issues/442)) - Bump testcontainers-java-tarantool version to 1.2.0 ([#442](https://github.com/tarantool/cartridge-java/issues/442)) - Bump netty version to 4.1.104.Final ([#446](https://github.com/tarantool/cartridge-java/issues/446)) +- Bump msgpack-java version to 0.9.6 ### Features diff --git a/profile.jfc b/profile.jfc new file mode 100644 index 00000000..2158029e --- /dev/null +++ b/profile.jfc @@ -0,0 +1,809 @@ + + + + + true + everyChunk + + + + true + 1000 ms + + + + true + everyChunk + + + + true + 1000 ms + + + + true + true + + + + true + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + + + + false + true + 0 ms + + + + false + true + + + + false + + + + true + beginChunk + + + + true + beginChunk + + + + true + 10 ms + + + + true + 20 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + true + + + + true + 60 s + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + everyChunk + + + + true + everyChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + false + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + true + + + + true + true + + + + true + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + true + + + + true + + + + false + everyChunk + + + + false + + + + true + true + 0 ns + + + + true + beginChunk + + + + true + 1000 ms + + + + true + 100 ms + + + + true + 10 s + + + + true + + + + false + + + + true + beginChunk + + + + true + everyChunk + + + + true + 100 ms + + + + true + beginChunk + + + + true + everyChunk + + + + true + + + + true + beginChunk + + + + true + beginChunk + + + + true + 10 s + + + + true + 1000 ms + + + + true + 10 s + + + + true + beginChunk + + + + true + endChunk + + + + true + 5 s + + + + true + beginChunk + + + + true + everyChunk + + + + true + true + + + + true + true + + + + true + everyChunk + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + + + + false + true + + + + true + 1000 ms + + + + true + + + + true + + + + true + + + + true + + + + true + 10 ms + + + + true + 0 ms + + + + 10 ms + true + + + + true + 10 ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 ms + + 10 ms + + 10 ms + + false + + + + diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java index 4792b062..527541b9 100644 --- a/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java +++ b/src/test/java/io/tarantool/driver/benchmark/ClusterBenchmarkRunner.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -23,35 +24,61 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; -@Fork(value = 1, jvmArgsAppend = "-Xmx1G") +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Fork(value = 1, jvmArgsAppend = { + "-Xms1G", "-Xmx1G", "-XX:+UseG1GC", //"-XX:+UnlockCommercialFeatures", + "-XX:+FlightRecorder", + "--add-opens=java.base/java.nio=ALL-UNNAMED", "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", + "-XX:StartFlightRecording=settings=/home/fedora/sources/cartridge-java/profile.jfc" +}) public class ClusterBenchmarkRunner { private static final String TEST_SPACE = "test_space"; private static final String TEST_PROFILE = "test__profile"; + private static final String CLUSTER_INIT_SCRIPT = "org/testcontainers/containers/cluster_benchmark.lua"; + + private static Logger logger = LoggerFactory.getLogger(ClusterBenchmarkRunner.class); public static void main(String[] args) throws Exception { org.openjdk.jmh.Main.main(args); } @Benchmark + @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 2) @Measurement(iterations = 10) - @OperationsPerInvocation(2) - public void getSpaceObject(ClusterTarantoolSetup plan, Blackhole bh) { - TarantoolSpaceOperations> testSpace = - plan.tarantoolClient.space(TEST_SPACE); - bh.consume(testSpace); - - TarantoolSpaceOperations> profileSpace = - plan.tarantoolClient.space(TEST_PROFILE); - bh.consume(profileSpace); + @OperationsPerInvocation(2000) + public void writeDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futuresHolder) { + // 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(plan.tarantoolClient.callForSingleResult( + "custom_crud_insert_one_record" , Arrays.asList(TEST_SPACE, tarantoolTuple), Map.class)); + tarantoolTuple = plan.tupleFactory.create(1_000_000 + nextId, null, uuid, 50_000 + nextId, 100_000 + i); + futuresHolder.allFutures.add(plan.tarantoolClient.callForSingleResult( + "custom_crud_insert_one_record" , Arrays.asList(TEST_PROFILE, tarantoolTuple), Map.class)); + } + nextId++; + plan.nextTestSpaceId = nextId; + plan.nextProfileSpaceId = nextId; } @Benchmark @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 2) @Measurement(iterations = 10) @OperationsPerInvocation(2000) - public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) { + public void writeDataUsingSpaceAPI( + ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces) { // Fill 10000 rows into both spaces TarantoolTuple tarantoolTuple; String uuid; @@ -71,14 +98,18 @@ public void writeData(ClusterTarantoolSetup plan, FuturesHolder futuresHolder, S @Benchmark @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 2) @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; + public void readDataUsingCallAPI( + ClusterTarantoolSetup plan, FuturesHolder futuresHolder, ClusterDataInit clusterDataInit) { + boolean coin; + String spaceName; long nextId; for (int i = 0; i < 1_000; i++) { nextId = Math.round(Math.random() * 10_000) + 1_000_000; + coin = Math.random() - 0.5 > 0; + spaceName = coin ? TEST_SPACE : TEST_PROFILE; futuresHolder.allFutures.add( plan.tarantoolClient.callForSingleResult( "custom_crud_get_one_record", Arrays.asList(spaceName, nextId), List.class) @@ -88,17 +119,20 @@ public void readDataUsingCallAPI(ClusterTarantoolSetup plan, FuturesHolder futur @Benchmark @BenchmarkMode(Mode.Throughput) + @Warmup(iterations = 2) @Measurement(iterations = 10) @OperationsPerInvocation(1000) public void readDataUsingSpaceAPI( - ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, Blackhole bh) { - boolean coin = Math.random() - 0.5 > 0; - TarantoolSpaceOperations> space = coin ? - spaces.testSpace : spaces.profileSpace; - String pkFieldName = coin ? "id" : "profile_id"; + ClusterTarantoolSetup plan, FuturesHolder futuresHolder, Spaces spaces, ClusterDataInit clusterDataInit) { + boolean coin; + TarantoolSpaceOperations> space; + String pkFieldName; long nextId; for (int i = 0; i < 1_000; i++) { nextId = Math.round(Math.random() * 10_000) + 1_000_000; + coin = Math.random() - 0.5 > 0; + space = coin ? spaces.testSpace : spaces.profileSpace; + pkFieldName = coin ? "id" : "profile_id"; futuresHolder.allFutures.add( space.select(Conditions.indexEquals(pkFieldName, Collections.singletonList(nextId))) ); @@ -109,14 +143,14 @@ public void readDataUsingSpaceAPI( public static class FuturesHolder { final List> allFutures = new ArrayList<>(2_000); - @Setup(Level.Invocation) - public void doSetup() { - allFutures.clear(); - } - @TearDown(Level.Invocation) public void doTeardown() { - allFutures.forEach(CompletableFuture::join); + try { + allFutures.forEach(CompletableFuture::join); + allFutures.clear(); + } catch (Exception e) { + e.printStackTrace(); + } } } @@ -131,4 +165,13 @@ public void doSetup(ClusterTarantoolSetup plan) { profileSpace = plan.tarantoolClient.space(TEST_PROFILE); } } + + @State(Scope.Thread) + public static class ClusterDataInit { + + @Setup(Level.Iteration) + public void doSetup(ClusterTarantoolSetup plan) throws Exception { + plan.tarantoolContainer.executeScript(CLUSTER_INIT_SCRIPT); + } + } } diff --git a/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java index c1ce5310..39a4d4dc 100644 --- a/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java +++ b/src/test/java/io/tarantool/driver/benchmark/ClusterTarantoolSetup.java @@ -37,7 +37,6 @@ public class ClusterTarantoolSetup { "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)); @@ -55,8 +54,8 @@ private void initClient() { new TarantoolServerAddress(tarantoolContainer.getRouterHost(), tarantoolContainer.getMappedPort(3303)) ) .withCredentials(tarantoolContainer.getUsername(), tarantoolContainer.getPassword()) - .withConnections(10) - .withEventLoopThreadsNumber(10) + .withConnections(2) + .withEventLoopThreadsNumber(2) .withRequestTimeout(10000) .withProxyMethodMapping() .build(); diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua index f0bdb7e0..c1f5e7e4 100644 --- a/src/test/resources/cartridge/app/roles/api_router.lua +++ b/src/test/resources/cartridge/app/roles/api_router.lua @@ -100,6 +100,10 @@ local function custom_crud_get_one_record(space_name, tuple_id) return crud.get(space_name, {tuple_id}).rows[1] end +local function custom_crud_insert_one_record(space_name, tuple) + return crud.insert(space_name, tuple) +end + local function raising_error() error("Test error: raising_error() called") end @@ -251,6 +255,7 @@ local function init(opts) rawset(_G, 'crud_error_timeout', crud_error_timeout) rawset(_G, 'custom_crud_select', custom_crud_select) rawset(_G, 'custom_crud_get_one_record', custom_crud_get_one_record) + rawset(_G, 'custom_crud_insert_one_record', custom_crud_insert_one_record) rawset(_G, 'get_routers_status', get_routers_status) rawset(_G, 'init_router_status', init_router_status) rawset(_G, 'test_no_such_procedure', test_no_such_procedure) diff --git a/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua b/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua new file mode 100644 index 00000000..72da5926 --- /dev/null +++ b/src/test/resources/org/testcontainers/containers/cluster_benchmark.lua @@ -0,0 +1,10 @@ +local crud = require('crud') +local uuid = require('uuid') + +crud.truncate('test_space') +crud.truncate('test__profile') + +for i = 1, 10000 do + crud.insert('test_space', {1000000 + i, nil, uuid.new(), 200000 + i}) + crud.insert('test__profile', {1000000 + i, nil, uuid.new(), 50000 + i, 100000 + i}) +end