Redisson

JavaCache LibraryRedisDistributed SystemNettyIn-Memory

GitHub Overview

redisson/redisson

Redisson - Valkey & Redis Java client. Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..

Stars24,074
Watchers871
Forks5,483
Created:January 11, 2014
Language:Java
License:Apache License 2.0

Topics

cachedistributeddistributed-locksexecutorhibernatejavajsonlockmapmicronautquarkusqueueredisredis-clientschedulersessionspringtomcatvalkeyvalkey-client

Star History

redisson/redisson Star History
Data as of: 10/22/2025, 10:04 AM

Cache Library

Redisson

Overview

Redisson is a Redis/Valkey client library for Java that provides over 50 distributed objects and services, built on top of the Netty-based asynchronous event-driven framework as a high-performance Real-Time Data Platform.

Details

Redisson is a Redis and Valkey client library for Java that serves as an in-memory data grid providing over 50 distributed objects and services. It includes comprehensive features such as Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, MapReduce, Bloom filter, Spring integration, Tomcat integration, Scheduler, JCache API, Hibernate, RPC, and local cache. Built on the Netty asynchronous event-driven client-server framework, it's compatible with Redis 2.8+ and JDK 1.8+. Supporting Sync/Async/RxJava/Reactive APIs, it allows using familiar Java collections and data structures on top of Redis, providing virtually zero learning curve for Java developers who already know standard interfaces. It offers integration with Spring framework, Spring Boot Starter, Spring Cache, Spring Session, Spring Transaction Manager, Spring Cloud Stream, and Spring Data Redis. Compatible with major cloud providers including Amazon ElastiCache, Amazon MemoryDB, Azure Cache for Redis, Redis Enterprise, Google Cloud Memorystore, and many others. According to benchmark tests, Redisson PRO outperforms Jedis in speed and can improve Redis performance from 55,000-75,000 ops/sec to a blazing fast 100,000-213,000 ops/sec.

Pros and Cons

Pros

  • High Performance: Netty-based asynchronous processing for fast operations
  • Rich Features: Over 50 distributed objects and services available
  • Low Learning Curve: Uses standard Java collection interfaces
  • Multi-API Support: Supports sync, async, RxJava, and reactive APIs
  • Framework Integration: Deep integration with Spring, Hibernate, and others
  • Cloud Ready: Full compatibility with major cloud providers
  • Distributed Features: Advanced features like distributed locks, semaphores, MapReduce

Cons

  • Complexity: Rich features can lead to complex configuration and usage
  • Memory Usage: Relatively high memory consumption due to Netty and object management
  • Learning Curve: Advanced distributed features require time to master
  • Dependencies: Requires Netty and other dependency libraries
  • Overhead: Higher initialization cost compared to lightweight clients

Key Links

Code Examples

Installation and Basic Configuration

<!-- Maven dependency -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.30.0</version>
</dependency>

<!-- For Spring Boot integration -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.30.0</version>
</dependency>
// Basic connection setup
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {
    public static void main(String[] args) {
        // Create configuration object
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setPassword("password")
              .setDatabase(0)
              .setConnectionMinimumIdleSize(10)
              .setConnectionPoolSize(64)
              .setIdleConnectionTimeout(10000)
              .setConnectTimeout(10000)
              .setTimeout(3000)
              .setRetryAttempts(3)
              .setRetryInterval(1500);

        // Create Redisson client
        RedissonClient redisson = Redisson.create(config);
        
        // Shutdown after use
        redisson.shutdown();
    }
}

Basic Object Operations

import org.redisson.api.*;

public class BasicOperations {
    private RedissonClient redisson;
    
    public void basicOperations() {
        // RBucket - single value storage
        RBucket<String> bucket = redisson.getBucket("myBucket");
        bucket.set("Hello, Redisson!");
        String value = bucket.get();
        System.out.println(value); // "Hello, Redisson!"
        
        // Object with expiration
        bucket.set("temporary", 60, TimeUnit.SECONDS);
        
        // RMap - Map interface
        RMap<String, String> map = redisson.getMap("myMap");
        map.put("key1", "value1");
        map.put("key2", "value2");
        
        // Access like local Map
        String val = map.get("key1");
        boolean exists = map.containsKey("key2");
        map.remove("key1");
        
        // RList - List interface
        RList<String> list = redisson.getList("myList");
        list.add("item1");
        list.add("item2");
        list.add(0, "first");
        
        String first = list.get(0);
        list.remove("item1");
        
        // RSet - Set interface
        RSet<String> set = redisson.getSet("mySet");
        set.add("element1");
        set.add("element2");
        boolean added = set.add("element1"); // false - already exists
        
        // RQueue - Queue interface
        RQueue<String> queue = redisson.getQueue("myQueue");
        queue.offer("task1");
        queue.offer("task2");
        String task = queue.poll(); // "task1"
    }
}

Asynchronous Operations

import org.redisson.api.*;
import java.util.concurrent.CompletableFuture;

public class AsyncOperations {
    private RedissonClient redisson;
    
    public void asyncOperations() {
        RBucket<String> bucket = redisson.getBucket("asyncBucket");
        
        // Asynchronous set
        RFuture<Void> setFuture = bucket.setAsync("async value");
        setFuture.whenComplete((result, exception) -> {
            if (exception == null) {
                System.out.println("Set completed successfully");
            } else {
                System.err.println("Set failed: " + exception.getMessage());
            }
        });
        
        // Asynchronous get
        RFuture<String> getFuture = bucket.getAsync();
        getFuture.thenAccept(value -> {
            System.out.println("Retrieved value: " + value);
        });
        
        // Chained asynchronous operations
        bucket.setAsync("initial")
              .thenCompose(v -> bucket.getAsync())
              .thenCompose(value -> {
                  System.out.println("Current value: " + value);
                  return bucket.setAsync("updated");
              })
              .thenRun(() -> System.out.println("All operations completed"));
    }
}

Distributed Locking

import org.redisson.api.*;
import java.util.concurrent.TimeUnit;

public class DistributedLocking {
    private RedissonClient redisson;
    
    public void lockExample() {
        RLock lock = redisson.getLock("myLock");
        
        try {
            // Acquire lock (blocking)
            lock.lock();
            
            // Critical section
            System.out.println("Critical section executed");
            Thread.sleep(1000);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // Release lock
            lock.unlock();
        }
    }
    
    public void tryLockExample() {
        RLock lock = redisson.getLock("myTryLock");
        
        try {
            // Try to acquire lock with timeout
            boolean acquired = lock.tryLock(100, 10, TimeUnit.SECONDS);
            
            if (acquired) {
                try {
                    // Critical section
                    System.out.println("Lock acquired, executing critical section");
                    
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("Failed to acquire lock within timeout");
            }
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    public void multiLockExample() {
        RLock lock1 = redisson.getLock("lock1");
        RLock lock2 = redisson.getLock("lock2");
        RLock lock3 = redisson.getLock("lock3");
        
        // Acquire multiple locks simultaneously
        RLock multiLock = redisson.getMultiLock(lock1, lock2, lock3);
        
        try {
            multiLock.lock();
            
            // Process with all locks acquired
            System.out.println("All locks acquired");
            
        } finally {
            multiLock.unlock();
        }
    }
}

Semaphore and CountDownLatch

import org.redisson.api.*;

public class SynchronizationPrimitives {
    private RedissonClient redisson;
    
    public void semaphoreExample() {
        RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
        
        try {
            // Set permit count (initialization)
            semaphore.trySetPermits(3);
            
            // Acquire permit
            semaphore.acquire();
            
            // Use resource
            System.out.println("Using limited resource");
            Thread.sleep(1000);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // Release permit
            semaphore.release();
        }
    }
    
    public void countDownLatchExample() {
        RCountDownLatch latch = redisson.getCountDownLatch("myLatch");
        
        // Set initial count for latch
        latch.trySetCount(3);
        
        // Count down in another thread
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 1 completed");
                
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 2 completed");
                
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 3 completed");
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        try {
            // Wait for all tasks to complete
            latch.await();
            System.out.println("All tasks completed!");
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Reactive/RxJava Operations

import org.redisson.api.*;
import org.redisson.api.redissonrx.*;
import reactor.core.publisher.Mono;
import io.reactivex.rxjava3.core.Single;

public class ReactiveOperations {
    private RedissonClient redisson;
    
    public void reactiveExample() {
        // Get reactive client
        RedissonReactiveClient reactiveClient = redisson.reactive();
        
        RBucketReactive<String> bucket = reactiveClient.getBucket("reactiveBucket");
        
        // Chain reactive operations
        Mono<Void> operation = bucket.set("reactive value")
            .then(bucket.get())
            .doOnNext(value -> System.out.println("Value: " + value))
            .then(bucket.delete())
            .then();
        
        // Execute
        operation.subscribe(
            result -> System.out.println("Operation completed"),
            error -> System.err.println("Error: " + error.getMessage())
        );
    }
    
    public void rxJavaExample() {
        // Get RxJava client
        RedissonRxClient rxClient = redisson.rxJava();
        
        RBucketRx<String> bucket = rxClient.getBucket("rxBucket");
        
        // Chain RxJava operations
        Single<String> operation = bucket.set("rx value")
            .andThen(bucket.get())
            .doOnSuccess(value -> System.out.println("RxJava Value: " + value));
        
        // Execute
        operation.subscribe(
            result -> System.out.println("RxJava operation completed: " + result),
            error -> System.err.println("RxJava error: " + error.getMessage())
        );
    }
}

Pub/Sub Functionality

import org.redisson.api.*;

public class PubSubOperations {
    private RedissonClient redisson;
    
    public void publishSubscribe() {
        // Publisher
        RTopic topic = redisson.getTopic("myTopic");
        
        // Subscriber
        topic.addListener(String.class, (channel, msg) -> {
            System.out.println("Received message: " + msg + " from channel: " + channel);
        });
        
        // Send message
        topic.publish("Hello, subscribers!");
        
        // Pattern matching subscription
        RPatternTopic patternTopic = redisson.getPatternTopic("news.*");
        patternTopic.addListener(String.class, (pattern, channel, msg) -> {
            System.out.println("Pattern: " + pattern + ", Channel: " + channel + ", Message: " + msg);
        });
        
        // Send to channels matching pattern
        redisson.getTopic("news.sports").publish("Sports news update");
        redisson.getTopic("news.tech").publish("Tech news update");
    }
    
    public void reliableTopic() {
        // Reliable topic (message persistence)
        RReliableTopic topic = redisson.getReliableTopic("reliableTopic");
        
        String listenerId = topic.addListener(String.class, (channel, msg) -> {
            System.out.println("Reliable message: " + msg);
        });
        
        // Send messages
        topic.publish("Reliable message 1");
        topic.publish("Reliable message 2");
        
        // Remove listener
        topic.removeListener(listenerId);
    }
}

Transaction Processing

import org.redisson.api.*;

public class TransactionOperations {
    private RedissonClient redisson;
    
    public void transactionExample() {
        RTransaction transaction = redisson.createTransaction(TransactionOptions.defaults());
        
        try {
            // Operations within transaction
            RBucket<String> bucket = transaction.getBucket("txBucket");
            RMap<String, String> map = transaction.getMap("txMap");
            
            bucket.set("transaction value");
            map.put("key1", "value1");
            map.put("key2", "value2");
            
            // Commit transaction
            transaction.commit();
            System.out.println("Transaction committed successfully");
            
        } catch (Exception e) {
            // Rollback on error
            transaction.rollback();
            System.err.println("Transaction rolled back: " + e.getMessage());
        }
    }
    
    public void batchOperations() {
        // Batch operations (pipelining)
        RBatch batch = redisson.createBatch();
        
        RBucketAsync<String> bucket1 = batch.getBucket("batch1");
        RBucketAsync<String> bucket2 = batch.getBucket("batch2");
        RMapAsync<String, String> map = batch.getMap("batchMap");
        
        // Add operations to batch
        bucket1.setAsync("batch value 1");
        bucket2.setAsync("batch value 2");
        map.putAsync("batchKey", "batchValue");
        
        // Execute batch
        BatchResult<?> results = batch.execute();
        System.out.println("Batch executed, results count: " + results.getResponses().size());
    }
}

MapReduce Processing

import org.redisson.api.*;
import org.redisson.mapreduce.*;

public class MapReduceOperations {
    private RedissonClient redisson;
    
    public void mapReduceExample() {
        RMap<String, String> map = redisson.getMap("sourceMap");
        
        // Insert test data
        map.put("line1", "Alice was beginning to get very tired");
        map.put("line2", "of sitting by her sister on the bank");
        map.put("line3", "and of having nothing to do");
        
        // Configure MapReduce task
        RMapReduce<String, String, String, Integer> mapReduce = map
            .<String, Integer>mapReduce()
            .mapper(new WordMapper())
            .reducer(new WordReducer());
        
        // Execute
        Map<String, Integer> result = mapReduce.execute();
        
        result.forEach((word, count) -> 
            System.out.println(word + ": " + count));
    }
    
    // Mapper class
    public static class WordMapper implements RMapper<String, String, String, Integer> {
        @Override
        public void map(String key, String value, RCollector<String, Integer> collector) {
            String[] words = value.toLowerCase().split("\\W+");
            for (String word : words) {
                if (!word.isEmpty()) {
                    collector.emit(word, 1);
                }
            }
        }
    }
    
    // Reducer class
    public static class WordReducer implements RReducer<String, Integer> {
        @Override
        public Integer reduce(String key, Iterator<Integer> values) {
            int sum = 0;
            while (values.hasNext()) {
                sum += values.next();
            }
            return sum;
        }
    }
}

Spring Boot Integration

// application.yml
/*
spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://localhost:6379"
          password: null
          database: 0
          connectionMinimumIdleSize: 10
          connectionPoolSize: 64
          idleConnectionTimeout: 10000
          connectTimeout: 10000
          timeout: 3000
*/

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.redisson.api.*;

@Service
public class RedissonService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    public void cacheUserData(String userId, Object userData) {
        RBucket<Object> bucket = redissonClient.getBucket("user:" + userId);
        bucket.set(userData, 1, TimeUnit.HOURS);
    }
    
    public Object getUserData(String userId) {
        RBucket<Object> bucket = redissonClient.getBucket("user:" + userId);
        return bucket.get();
    }
    
    public void addToUserSessions(String userId, String sessionId) {
        RSet<String> sessions = redissonClient.getSet("sessions:" + userId);
        sessions.add(sessionId);
        sessions.expire(24, TimeUnit.HOURS);
    }
    
    public boolean isUserOnline(String userId) {
        RSet<String> sessions = redissonClient.getSet("sessions:" + userId);
        return !sessions.isEmpty();
    }
}

Performance Optimization

public class PerformanceOptimization {
    
    public RedissonClient createOptimizedClient() {
        Config config = new Config();
        
        // Optimize single server configuration
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              // Connection pool settings
              .setConnectionPoolSize(64)
              .setConnectionMinimumIdleSize(10)
              // Timeout settings
              .setConnectTimeout(10000)
              .setTimeout(3000)
              .setIdleConnectionTimeout(10000)
              // Retry settings
              .setRetryAttempts(3)
              .setRetryInterval(1500)
              // Disable DNS monitoring (performance improvement)
              .setDnsMonitoringInterval(-1);
        
        // Performance settings
        config.setThreads(16); // NIO thread count
        config.setNettyThreads(32); // Netty thread count
        config.setCodec(org.redisson.codec.KryoCodec.INSTANCE); // Fast serialization
        
        return Redisson.create(config);
    }
    
    public void localCacheExample() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        
        RedissonClient redisson = Redisson.create(config);
        
        // Map with local cache
        LocalCachedMapOptions<String, String> options = LocalCachedMapOptions.<String, String>defaults()
            .evictionPolicy(LocalCachedMapOptions.EvictionPolicy.LRU)
            .cacheSize(1000)
            .timeToLive(10, TimeUnit.MINUTES)
            .maxIdle(5, TimeUnit.MINUTES);
        
        RLocalCachedMap<String, String> map = redisson.getLocalCachedMap("cachedMap", options);
        
        // First access from Redis, subsequent from local cache
        map.put("key1", "value1");
        String value = map.get("key1"); // Fast retrieval from local cache
    }
}