Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions performance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Spring Data Valkey Performance Tests

Performance benchmarks for Spring Data Valkey operations across different clients.

## Prerequisites

- JDK 17 or higher
- Maven 3.9.9 or higher (use `../mvnw` from root directory)
- Valkey server running on `localhost:6379` (or configure connection in tests)

If using a development build of Spring Data Valkey, first install to your local Maven repository before running the tests:
```bash
# From project root
$ ./mvnw clean install -DskipTests
```

See instructions on starting a Valkey server using the `Makefile` in the root [README](../README.md#building-from-source). The standalone instance started by the Makefile is used in these tests.

## Running Tests

### Template Performance Test

Test ValkeyTemplate operations (`SET`, `GET`, `DELETE`) with different clients:

```bash
$ mvn -q compile exec:java -Dclient=valkeyglide
$ mvn -q compile exec:java -Dclient=lettuce
$ mvn -q compile exec:java -Dclient=jedis
```

### Multi-Threaded Performance Test

Test template use across mulitple threads with different clients:

```bash
$ mvn -q compile exec:java@threaded-test -Dclient=valkeyglide
$ mvn -q compile exec:java@threaded-test -Dclient=lettuce
$ mvn -q compile exec:java@threaded-test -Dclient=jedis
```

### Direct Client Performance Test

Test direct client operations without Spring Data Valkey (for comparison):

```bash
$ mvn -q compile exec:java@direct-test -Dclient=valkeyglide
$ mvn -q compile exec:java@direct-test -Dclient=lettuce
$ mvn -q compile exec:java@direct-test -Dclient=jedis
```

### Multi-Threaded Direct Client Performance Test

Test direct client operations across multiple threads:

```bash
$ mvn -q compile exec:java@threaded-direct-test -Dclient=valkeyglide
$ mvn -q compile exec:java@threaded-direct-test -Dclient=lettuce
$ mvn -q compile exec:java@threaded-direct-test -Dclient=jedis
```

### Template Load Test

Test ValkeyTemplate operations (`SET`, `GET`, `DELETE`) with different clients and concurrency levels.

Parameters:
- `client`: Client type - `valkeyglide`, `lettuce`, `jedis` (default: `valkeyglide`)
- `threads`: Number of threads (default: `10`)
- `operations`: Operations per thread (default: `50`)

```bash
# Compare a single client with different concurrency levels
$ mvn -q compile exec:java@load-test -Dclient=valkeyglide -Dthreads=5 -Doperations=20
$ mvn -q compile exec:java@load-test -Dclient=valkeyglide -Dthreads=20 -Doperations=100

# Comapre across different clients
$ mvn -q compile exec:java@load-test -Dclient=valkeyglide -Dthreads=100 -Doperations=200
$ mvn -q compile exec:java@load-test -Dclient=lettuce -Dthreads=100 -Doperations=200
$ mvn -q compile exec:java@load-test -Dclient=jedis -Dthreads=100 -Doperations=200
```
108 changes: 108 additions & 0 deletions performance/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.valkey.springframework.data</groupId>
<artifactId>spring-data-valkey-performance</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<name>Spring Data Valkey - Performance Tests</name>
<description>Performance benchmarks for Spring Data Valkey operations across different clients</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
<spring-data-valkey.version>3.5.1</spring-data-valkey.version>
<valkey-glide.version>2.1.1</valkey-glide.version>
<lettuce.version>6.4.0.RELEASE</lettuce.version>
<jedis.version>5.2.0</jedis.version>
<slf4j.version>2.0.9</slf4j.version>
</properties>

<dependencies>
<dependency>
<groupId>io.valkey.springframework.data</groupId>
<artifactId>spring-data-valkey</artifactId>
<version>${spring-data-valkey.version}</version>
</dependency>
<dependency>
<groupId>io.valkey</groupId>
<artifactId>valkey-glide</artifactId>
<version>${valkey-glide.version}</version>
<classifier>${os.detected.classifier}</classifier>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuce.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>

<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>performance.TemplatePerformanceTest</mainClass>
<cleanupDaemonThreads>false</cleanupDaemonThreads>
</configuration>
<executions>
<execution>
<id>threaded-test</id>
<configuration>
<mainClass>performance.MultiThreadedPerformanceTest</mainClass>
</configuration>
</execution>
<execution>
<id>direct-test</id>
<configuration>
<mainClass>performance.DirectClientPerformanceTest</mainClass>
</configuration>
</execution>
<execution>
<id>threaded-direct-test</id>
<configuration>
<mainClass>performance.ThreadedDirectClientPerformanceTest</mainClass>
</configuration>
</execution>
<execution>
<id>load-test</id>
<configuration>
<mainClass>performance.TemplateLoadTest</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
151 changes: 151 additions & 0 deletions performance/src/main/java/performance/DirectClientPerformanceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed 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
*
* https://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 performance;

import glide.api.GlideClient;
import glide.api.models.GlideString;
import glide.api.models.configuration.GlideClientConfiguration;
import glide.api.models.configuration.NodeAddress;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import redis.clients.jedis.Jedis;

/**
* Direct client performance test without Spring Data Valkey overhead.
*/
public class DirectClientPerformanceTest {

private static final int OPERATIONS = 10000;
private static final String KEY_PREFIX = "direct:test:";

public static void main(String[] args) throws Exception {
String clientType = System.getProperty("client", "valkeyglide");

System.out.println("Running Direct Client Performance Test");
System.out.println("Client: " + clientType);
System.out.println("Operations: " + OPERATIONS);
System.out.println("----------------------------------------");

switch (clientType.toLowerCase()) {
case "valkeyglide" -> testValkeyGlide();
case "lettuce" -> testLettuce();
case "jedis" -> testJedis();
default -> throw new IllegalArgumentException("Unknown client: " + clientType);
}
}

private static void testValkeyGlide() throws Exception {
GlideClientConfiguration config = GlideClientConfiguration.builder()
.address(NodeAddress.builder().host("localhost").port(6379).build())
.build();

try (GlideClient client = GlideClient.createClient(config).get()) {
// SET operations
long start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
client.set(GlideString.of(KEY_PREFIX + i), GlideString.of("value" + i)).get();
}
long setTime = System.nanoTime() - start;
printResult("SET", setTime);

// GET operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
client.get(GlideString.of(KEY_PREFIX + i)).get();
}
long getTime = System.nanoTime() - start;
printResult("GET", getTime);

// DELETE operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
client.del(new GlideString[]{GlideString.of(KEY_PREFIX + i)}).get();
}
long deleteTime = System.nanoTime() - start;
printResult("DELETE", deleteTime);
}
}

private static void testLettuce() {
RedisClient client = RedisClient.create(RedisURI.create("redis://localhost:6379"));

try (StatefulRedisConnection<String, String> connection = client.connect()) {
RedisCommands<String, String> commands = connection.sync();

// SET operations
long start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
commands.set(KEY_PREFIX + i, "value" + i);
}
long setTime = System.nanoTime() - start;
printResult("SET", setTime);

// GET operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
commands.get(KEY_PREFIX + i);
}
long getTime = System.nanoTime() - start;
printResult("GET", getTime);

// DELETE operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
commands.del(KEY_PREFIX + i);
}
long deleteTime = System.nanoTime() - start;
printResult("DELETE", deleteTime);
} finally {
client.shutdown();
}
}

private static void testJedis() {
try (Jedis jedis = new Jedis("localhost", 6379)) {
// SET operations
long start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
jedis.set(KEY_PREFIX + i, "value" + i);
}
long setTime = System.nanoTime() - start;
printResult("SET", setTime);

// GET operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
jedis.get(KEY_PREFIX + i);
}
long getTime = System.nanoTime() - start;
printResult("GET", getTime);

// DELETE operations
start = System.nanoTime();
for (int i = 0; i < OPERATIONS; i++) {
jedis.del(KEY_PREFIX + i);
}
long deleteTime = System.nanoTime() - start;
printResult("DELETE", deleteTime);
}
}

private static void printResult(String operation, long durationNanos) {
long durationMs = durationNanos / 1_000_000;
System.out.printf("%s: %,d ops/sec (%.2f ms total)%n",
operation, (long) (OPERATIONS * 1000.0 / durationMs), durationMs / 1.0);
}
}
Loading