Redisson
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..
Topics
Star History
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
- Redisson GitHub Repository
- Redisson Official Website
- Redisson Official Documentation
- Redis Official Documentation
- Netty Official Website
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
}
}