Learnitweb

Testing Redis Performance with Spring Boot

In this tutorial, we will explore how to test the performance of Redis using Spring Boot. We will compare Spring Data Redis (reactive) and native Redis clients to see the differences in execution speed for a large number of operations.


1. Project Setup

Before starting, ensure your project has the necessary dependencies:

Dependencies

  • Spring Boot Starter Data Redis (Reactive)
    For reactive Redis operations.
  • Lettuce (Reactive Redis Client)
    Provides low-level reactive Redis operations.

Add these to your pom.xml or build.gradle:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
</dependency>

Ensure your Redis server is running locally or provide the IP and port in application.properties if it is running remotely:

spring.redis.host=127.0.0.1
spring.redis.port=6379

2. Understanding Redis Templates

Spring Data Redis exposes template beans to interact with Redis:

  • ReactiveRedisTemplate<K, V> for reactive operations.
  • Supports different operations like:
    • Value operations: increment, set, get, delete.
    • Hash operations: put, get, delete.

The template works like JDBC Template, providing a high-level abstraction for Redis operations.


3. Performance Test Plan

We want to measure how long it takes to execute a large number of Redis operations:

  • Test scenario: Increment a counter 500,000 times in Redis.
  • Compare execution times:
    1. Using Spring Data Redis (Reactive).
    2. Using native Redis client (Lettuce).

Step 1: Create a Reactive Redis Template

@Autowired
private ReactiveRedisTemplate<String, String> reactiveRedisTemplate;
  • This template allows reactive operations like increment, get, delete on keys.

Step 2: Prepare Value Operations

ReactiveValueOperations<String, String> valueOps = reactiveRedisTemplate.opsForValue();
  • valueOps.increment(key) increments the value of a key.
  • We will perform 500,000 increment operations to measure performance.

4. Measure Execution Time

Step 1: Record Start Time

long startTime = System.currentTimeMillis();

Step 2: Execute Operations

  • Loop 500,000 times, incrementing a counter in Redis:
for (int i = 0; i < 500_000; i++) {
    valueOps.increment("counter").subscribe();
}

Step 3: Record End Time

long endTime = System.currentTimeMillis();
System.out.println("Time taken: " + (endTime - startTime) + " ms");

This measures the total time taken for 500,000 operations.


5. Warm-Up Runs

  • The first run may be slower due to initialization overhead.
  • Run the test 3 times and consider the average time after warm-up.

6. Observed Performance

Example observations:

ClientAverage Time (500,000 ops)
Spring Data Redis Reactive~17 seconds
Native Redis (Lettuce)~10.5 seconds
  • Using native Redis client significantly improves performance (~7 seconds faster in this test).
  • The performance difference exists because Spring Data Redis reactive template introduces some overhead.

7. Using Native Redis with Spring Boot

  • If you want maximum performance, use Lettuce directly:
@Autowired
private RedisClient redisClient; // Native Lettuce client

StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> commands = connection.sync();

for (int i = 0; i < 500_000; i++) {
    commands.incr("counter");
}
  • This approach bypasses Spring Data Redis templates and uses the native API.

8. Key Takeaways

  • Spring Data Redis Reactive is convenient but slightly slower due to abstraction overhead.
  • Native Redis clients like Lettuce provide better raw performance for bulk operations.
  • Always do warm-up runs to account for initial startup delays.
  • Reactive templates are good for non-blocking applications, but performance-sensitive operations may benefit from direct native clients.