Skip to content

Revisit performance bottlenecks in hot code paths using Lettuce through the reactive Template #2110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
vinsguru opened this issue Jul 1, 2021 · 4 comments
Assignees
Labels
type: task A general task

Comments

@vinsguru
Copy link

vinsguru commented Jul 1, 2021

I was trying to run this simple performance test with Spring Data Redis vs lettuce.

Spring Data Redis seems to be significantly slow with default configuration compared to lettuce. (The throughput is 50% less with Spring Data Redis). Is this much difference expected?

You can check yourself wit this code.

Spring Boot : 2.5.2
spring-boot-starter-data-redis-reactive

   @RepeatedTest(3)
    public void springDataRedisPerformance(){
        ReactiveValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        long before = System.currentTimeMillis();
        Mono<Void> mono = Flux.range(1, 500_000)
                .flatMap(i -> valueOperations.increment("user:1"))
                .then();
        StepVerifier.create(mono)
                .verifyComplete();
        System.out.println((System.currentTimeMillis() - before) + " ms");
    }

    @RepeatedTest(3)
    public void lettucePerformance() throws InterruptedException {
        RedisClient redisClient = RedisClient.create("redis://localhost:6379/0");
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();

        long before = System.currentTimeMillis();
        Mono<Void> mono = Flux.range(1, 500_000)
                .flatMap(i -> reactiveCommands.incr("user:1"))
                .then();

        StepVerifier.create(mono).verifyComplete();
        System.out.println((System.currentTimeMillis() - before)  + " ms");
    }
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 1, 2021
@mp911de
Copy link
Member

mp911de commented Jul 2, 2021

There are some odd things in the code posted here.

First, creating a new RedisClient instance for each test run which is associated with creating thread pools each time that pollute your resources. Secondly, a. lot of additional load is put onto the code paths by using reactive API chaining. Finally, a proper benchmark consists of a warmup phase along with warmup iterations followed by multiple measurement iterations.

We're happy to review profiler findings if you can share some of these with us.

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label Jul 2, 2021
@vinsguru
Copy link
Author

vinsguru commented Jul 2, 2021

@mp911de

I create one RedisClient. then make 500_000 calls. This is the actual test. @RepeatedTest is ignoring the first run for warming up and consider subsequent runs. You can ignore RepeatedTest if it is confusing or make it as instance level variable. The point here is - the result is still same.

     Mono<Void> mono = Flux.range(1, 500_000)
                .flatMap(i -> reactiveCommands.incr("user:1"))
                .then();

I see better performance with Lettuce. Not with Spring Redis Template. Thats the question.

Feel free to close!

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 2, 2021
@mp911de
Copy link
Member

mp911de commented Jul 15, 2021

I recorded a profiling session and there are a few areas that we can optimize. A benchmark reports about 30% of performance difference between plain Lettuce and Spring Data Redis usage (6443 ms vs. 4044 ms)

Spring Data Redis Profiling.snapshot.zip
Bildschirmfoto 2021-07-15 um 14 07 06

@mp911de mp911de added type: task A general task and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Jul 15, 2021
@mp911de mp911de changed the title Spring Data Redis vs Lettuce Performance Revisit performance bottlenecks in hot code paths using Lettuce through the reactive Template Jul 15, 2021
@mp911de mp911de self-assigned this Jul 21, 2021
@mp911de
Copy link
Member

mp911de commented Jul 21, 2021

With a proper benchmark we get:

Benchmark                                                  Mode  Cnt       Score       Error  Units
ReactiveRedisTemplateBenchmark.clientOnly                 thrpt   10   21845,692 ±   828,334  ops/s
ReactiveRedisTemplateBenchmark.clientReactiveConcatMap    thrpt   10   30100,343 ±   975,742  ops/s
ReactiveRedisTemplateBenchmark.clientReactiveFlatMap      thrpt   10  115879,389 ± 13242,159  ops/s
ReactiveRedisTemplateBenchmark.templateReactiveConcatMap  thrpt   10   26251,948 ±  1976,017  ops/s
ReactiveRedisTemplateBenchmark.templateReactiveFlatMap    thrpt   10   83184,567 ±  6757,851  ops/s

Baseline -> Spring Data overhead concatMap ~ 14%, flatMap 38%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: task A general task
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants