Overview of Redisson: The Redis Java Client
Check out this comprehensive overview of Redisson!
Join the DZone community and get the full member experience.
Join For FreeWhy Redisson?
Redis is an open-source, in-memory data structure store that can be used as a NoSQL key-value database, as well as a cache and message broker.
With lightning-fast speed, high availability and scalability, and support for a rich variety of data structures, it’s little wonder that developers are using Redis to build resilient and high-performance, non-relational databases.
According to a 2019 survey by programming Q&A website Stack Overflow, Redis is the “most loved” database technology, ahead of more established alternatives such as Oracle, MySQL, Microsoft SQL Server, and MongoDB.
You may also like: Distributed Java Collections in Redis With Redisson
Although Redis has a lot of features and benefits, users should be aware that Redis is not compatible with programming languages such as Java out-of-the-box. Rather, users who want to use Redis with Java need to use a third-party Java client library for Redis such as Redisson.
Redisson is a Redis client for Java that offers an in-memory data grid with support for many of the familiar Java collections, objects, and services. This rich feature set enables Java developers to quickly and easily get started with Redis, using the conventions that they are familiar with.
Redisson enables developers to focus less time on the programming aspect of Redis and devote more time to important concerns such as data modeling and application logic.
Based on the Netty asynchronous event-driven client-server framework, Redisson is compatible with Redis 2.8+ and JDK 1.8+. Redisson comes in two versions: the open-source Redisson project and Redisson PRO, which has greater speed and additional functionality.
This article will provide a comprehensive overview of everything you need to know about working with Redisson: configuring Redisson, Redis setup with Redisson, using Java objects and collections in Redis with Redisson, other Redisson features.
Maven Dependency
Large, complex Java projects often make use of build automation tools such as Apache Maven. If you use Maven to build your Java project, including support for Redisson is easy. Simply include the following lines in your pom.xml file:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.5</version>
</dependency>
This will provide the latest version of Redisson for your Java project (3.11.5 as of this writing). To make sure that you are using the most up-to-date Redisson version, check the Redisson project page on GitHub.
Gradle Dependency
Like Maven, Gradle is another open-source build automation tool for Java projects. Also like Maven, including support for Redisson in Gradle is extremely simple. Add the following line to your build.gradle file:
compile 'org.redisson:redisson:3.11.5'
Again, you can find the latest version of Redisson on the Redisson project page on GitHub.
Redis Setup
Naturally, the first step for using Redisson with Redis is to install Redis. You can find instructions for installing Redis on Linux and Mac OS X at the Redis Quick Start page. If you’re on a Windows machine, you can try using Microsoft’s unofficial port of Redis (although, note that this project is no longer actively maintained).
Once you’ve included the Redisson dependency via Maven or Gradle and installed Redis, the next step is to connect Redisson with Redis. Redisson supports connections to the following Redis configurations:
- Single node
- Master with slave nodes
- Sentinel nodes
- Clustered nodes
- Replicated nodes
The following line of Java code connects to a single node instance of Redis:
RedissonClient client = Redisson.create();
After executing this line of code, the client is running on the default port 6379. You can change this port number, as well as other Redisson settings, by passing in arguments to the Redisson.create()
method. This configuration can either be written directly in Java or loaded from an external file.
Configuring Redisson in Java
Below is an example of how to configure Redisson directly in Java:
Config config = new Config();
config.useSingleServer()
.setAddress("127.0.0.1:6379");
RedissonClient client = Redisson.create(config);
In this code, we first instantiate a Config
object, and then, we can configure it to use the IP address 127.0.0.1 with port number 6379.
The useSingleServer()
method indicates to Redis that we want to connect to a single node instance of Redis. The other options for connecting to different Redis configurations are:
useMasterSlaveServers()
: Master with slave nodesuseSentinelServers()
: Sentinel nodesuseClusterServers()
: Clustered nodes, including support of AWS ElastiCache Cluster and Azure Redis Cache.- useReplicatedServers(): Replicated nodes, including support of AWS ElastiCache and Azure Redis Cache.
Configuring Redisson From an External File
Alternatively, we can configure Redisson by loading settings from an external JSON or YAML file. Below is an example of loading Redisson settings from an external YAML file:
Config config = Config.fromYAML(new File("redisson.yaml"));
RedissonClient client = Redisson.create(config);
The default Redisson settings within the corresponding YAML file are:
singleServerConfig:
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
reconnectionTimeout: 3000
failedAttempts: 3
password: null
subscriptionsPerConnection: 5
clientName: null
address: "redis://127.0.0.1:6379"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 10
connectionPoolSize: 64
database: 0
dnsMonitoring: false
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.FstCodec> {}
useLinuxNativeEpoll: false
For detailed information about configuring Redisson, see the Configuration page on the Redisson wiki.
Redis-Based Java objects
Redisson includes support for a wide variety of Java objects. Individual instances of a Redisson object are serialized and stored in an available Redis node, or distributed in a cluster across multiple nodes.
The distributed Java objects in Redisson follow the specifications of the java.util.concurrent.atomic package. As such, you can perform lock-free, thread-safe, and atomic operations on the objects stored in Redis. Data remains consistent between different applications and servers.
In this section, we will discuss the different Java distributed objects in Redisson. For detailed information, consult the Distributed Objects page on the Redisson wiki.
ObjectHolder
The RBucket class in Redisson reimplements the ObjectHolder
class in Java. An RBucket
object is capable of holding any type of object. It has also Reactive and RxJava2 interfaces. Code example:
RBucket<Ledger> bucket = client.getBucket("ledger");
bucket.set(new Ledger());
Ledger ledger = bucket.get();
BinaryStreamHolder
The RBinaryStream interface in Redisson holds a binary stream. You can easily read from and write to the stream using the InputStream
and OutputStream
objects:
RBinaryStream stream = redisson.getBinaryStream("anyStream");
byte[] content = ...
stream.set(content);
InputStream is = stream.getInputStream();
byte[] readBuffer = new byte[512];
is.read(readBuffer);
OutputStream os = stream.getOuputStream();
byte[] contentToWrite = ...
os.write(contentToWrite);
GeospatialHolder
The RGeo interface in Redisson holds geospatial items. It has also Reactive and RxJava2 interfaces. Code example:
RGeo<String> geo = redisson.getGeo("test");
geo.add(new GeoEntry(13.361389, 38.115556, "Palermo"),
new GeoEntry(15.087269, 37.502669, "Catania"));
geo.addAsync(37.618423, 55.751244, "Moscow");
BitSet
The RBitSet interface in Redisson represents a bit vector that can expand as necessary, with a maximum size of 4,294,967,295 bits. It has also Reactive and RxJava2 interfaces. Code example:
RBitSet set = redisson.getBitSet("simpleBitset");
set.set(0, true);
set.set(1812, false);
set.clear(0);
AtomicLong
The RAtomicLong interface in Redisson reimplements the AtomicLong
class in Java, representing a long integer value that may be updated atomically. It has also Reactive and RxJava2 interfaces. Code example:
RAtomicLong atomicLong = client.getAtomicLong("myAtomicLong");
atomicLong.set(5);
atomicLong.incrementAndGet();
AtomicDouble
The RAtomicDouble interface in Redisson reimplements the AtomicDouble
class in Java, representing a double value that may be updated atomically. It also has Reactive and RxJava2 interfaces. Code example:
RAtomicDouble atomicDouble = redisson.getAtomicDouble("myAtomicDouble");
atomicDouble.set(2.81);
atomicDouble.addAndGet(4.11);
Topic
The RTopic interface in Redisson is used to implement a publish/subscribe messaging system. Subscribers can listen for messages for a particular topic. It also has Reactive and RxJava2 interfaces. Code example:
RTopic topic = redisson.getTopic("anyTopic");
topic.addListener(SomeObject.class, new MessageListener<SomeObject>() {
@Override
public void onMessage(String channel, SomeObject message) {
//...
}
});
BloomFilter
The RBloomFilter interface in Redisson is used to implement the Bloom filter data structure:
RBloomFilter<SomeObject> bloomFilter = redisson.getBloomFilter("sample");
// initialize bloom filter with
// expectedInsertions = 55000000
// falseProbability = 0.03
bloomFilter.tryInit(55000000L, 0.03);
bloomFilter.add(new SomeObject("field1Value", "field2Value"));
bloomFilter.add(new SomeObject("field5Value", "field8Value"));
bloomFilter.contains(new SomeObject("field1Value", "field8Value"));
HyperLogLog
The RHyperLogLog interface in Redisson provides access to the HyperLogLog
algorithm and data structure implemented in Redis. HyperLogLog
is used for estimating the number of unique elements in a multiset. It has also Reactive and RxJava2 interfaces. Code example:
RHyperLogLog<Integer> log = redisson.getHyperLogLog("log");
log.add(1);
log.add(2);
log.add(3);
log.count();
Redis-Based Java collections
Java collections in Redisson are handled the same way as objects. This allows you to perform lock-free, thread-safe, and atomic operations on the Java collections in Redisson.
The Java collections supported by Redisson are:
- Map
- Multimap
- Set
- SortedSet
- ScoredSortedSet
- LexSortedSet
- List
- Queue
- Deque
- BlockingQueue
- BoundedBlockingQueue
- BlockingDeque
- BlockingFairQueue
- DelayedQueue
- PriorityQueue
- PriorityDeque
For complete details about using these collections in Redisson, see the Distributed Collections page on the Redisson wiki.
Redis-Based Locks and Synchronizers
In Redisson, locks and synchronizers are distributed, allowing you to synchronize threads across multiple applications and servers. The Java locks and synchronizers supported by Redisson are:
- Lock
- FairLock
- MultiLock
- ReadWriteLock
- Semaphore
- PermitExpirableSemaphore
- CountDownLatch
For complete details about using these collections in Redisson, see the Distributed Locks and Synchronizers page on the Redisson wiki.
Lock
The RLock interface in Redisson is a distributed implementation of the Lock interface in Java. It has also Reactive and RxJava2 interfaces. Code example:
RLock lock = client.getLock("lock");
lock.lock();
// perform some long operations...
lock.unlock();
MultiLock
The RedissonMultiLock
class in Redisson allows users to manage multiple locks as a single unit:
RLock lock1 = clientInstance1.getLock("lock1");
RLock lock2 = clientInstance2.getLock("lock2");
RLock lock3 = clientInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
lock.lock();
// perform long running operation...
lock.unlock();
Semaphore
The RSemaphore interface in Redisson is used to control access to a shared resource through the use of a counter. It has also Reactive, and RxJava2 interfaces. Code example:
RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();
// or
semaphore.acquireAsync();
semaphore.acquire(23);
semaphore.tryAcquire();
semaphore.releaseAsync();
Redis-Based services
Redisson includes support for five types of distributed services: Remote Service, Live Object Service, Executor Service, Scheduled Executor Service, and MapReduce Service. For a complete guide to distributed services in Redisson, consult the Distributed Services page on the Redisson wiki.
Remote Service
This service allows Redisson users to execute remote procedure calls in Java using the Async, Reactive, and RxJava2 APIs. It includes two aspects, the server-side implementation and the client-side implementation.
The server-side registers an interface for remote invocation:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceImpl ledgerServiceImpl = new LedgerServiceImpl();
remoteService.register(LedgerServiceInterface.class, ledgerServiceImpl);
The client-side calls a method of the registered remote interface:
RRemoteService remoteService = client.getRemoteService();
LedgerServiceInterface ledgerService
= remoteService.get(LedgerServiceInterface.class);
List<String> entries = ledgerService.getEntries(10);
Live Object Service
“Live objects” in Redisson are an enhanced version of standard Java objects that can be shared between different machines and different JVMs. The fields of a live object are mapped to a Redis hash and can be accessed atomically, thanks to Redis’ single-threadedness.
The code below demonstrates the creation of a live object in Redis. The @RId
annotation designates a unique or identifying field:
@REntity
public class LedgerLiveObject {
@RId
private String name;
// getters and setters...
}
Once created, a live object can be used within an application and saved to Redis using the persist()
method:
RLiveObjectService service = client.getLiveObjectService();
LedgerLiveObject ledger = new LedgerLiveObject();
ledger.setName("ledger1");
ledger = service.persist(ledger);
Transactions
Transactions in Redis are atomic: either all of the commands in the transaction are processed, or none of them are. MULTI
, EXEC
, DISCARD
, and WATCH
are the four commands that are the foundation of Redis transactions. The MULTI
command allows for multiple commands within a transaction, while the EXEC
command executes all of the commands in the transaction.
Redisson supports executing transactions with the isolation level READ_COMMITTED
using locks during write operations. The objects that are eligible for transactions in Redisson include RMap
, RMapCache
, RLocalCachedMap
, RSet
, RSetCache
, and RBucket
.
The following code demonstrates the execution of a transaction in Redisson:
RTransaction transaction = redisson.createTransaction(TransactionOptions.defaults());
RMap<String, String> map = transaction.getMap("myMap");
map.put("1", "2");
String value = map.get("3");
RSet<String> set = transaction.getSet("mySet")
set.add(value);
try {
transaction.commit();
} catch(TransactionException e) {
transaction.rollback();
}
For more information, read the Transactions section on the Redisson wiki.
Pipelining
In Redis, pipelining is a feature that allows you to send multiple commands to the server in a batch as a single atomic operation, helping to reduce execution times. Pipelining is supported in Redisson with the RBatch class:
RBatch batch = client.createBatch();
batch.getMap("ledgerMap").fastPutAsync("1", "2");
batch.getMap("ledgerMap").putAsync("2", "5");
List<?> result = batch.execute();
Publish/subscribe
As discussed above, Redisson can be used to implement the publish/subscribe pattern (“pub/sub”) using the RTopic interface.
Below is an example of how to listen for published messages in Redisson:
RTopic subscribeTopic = client.getTopic("redisson");
subscribeTopic.addListener(CustomMessage.class, (channel, customMessage)
-> future.complete(customMessage.getMessage()));
subscribeTopic
is an RTopic instance that listens for messages from the “redisson” channel. The addListener()
method specifies how to handle incoming messages from that channel.
The following code demonstrates how to publish messages to a channel (possibly from another application or server):
RTopic publishTopic = client.getTopic("redisson");
long clientsReceivedMessage = publishTopic.publish(new CustomMessage("Hello world"));
Integration With Frameworks
Redisson is fully compatible with popular Java frameworks including:
- Spring Cache
- Hibernate Cache
- JCache
- Tomcat Session Manager
- Spring Session
- Spring PlatformTransactionManager
- Spring Boot starters
- More than 20 statistics monitoring solutions (JMX, NewRelic, etc.)
For more information about using Java frameworks with Redisson, consult the Integration with Frameworks page on the Redisson wiki.
Redis Cluster support
Redis Cluster enables Redis users to automatically shard data across multiple Redis nodes, improving the database’s scalability and availability. Thanks to the distributed nature of Redisson’s Java constructs, Redis Cluster is easily compatible with Redisson.
The example below illustrates the usage of Redisson with Redis Cluster:
package redis.demo;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
public class Application
{
public static void main( String[] args )
{
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:6379", "redis://127.0.0.1:6380");
RedissonClient redisson = Redisson.create(config);
// operations with Redis based Lock
// implements java.util.concurrent.locks.Lock
RLock lock = redisson.getLock("simpleLock");
lock.lock();
try {
// do some actions
} finally {
lock.unlock();
}
// operations with Redis based Map
// implements java.util.concurrent.ConcurrentMap
RMap<String, String> map = redisson.getMap("simpleMap");
map.put("mapKey", "This is a map value");
String mapValue = map.get("mapKey");
System.out.println("stored map value: " + mapValue);
redisson.shutdown();
}
}
Redis Sentinel support
Redis Sentinel is a high-availability solution for Redis that manages and monitors your Redis deployment. As with Redis Cluster, Redisson includes support for Redis Sentinel. You must specify at least one Redis Sentinel server and a master name when using Redisson with Redis Sentinel.
The example below illustrates the usage of Redisson with Redis Sentinel:
package redis.demo;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
/**
* Redis Sentinel Java example
*
*/
public class Application
{
public static void main( String[] args )
{
Config config = new Config();
config.useSentinelServers()
.addSentinelAddress("redis://127.0.0.1:6379")
.setMasterName("myMaster");
RedissonClient redisson = Redisson.create(config);
// perform operations
// implements java.util.concurrent.ConcurrentMap
RMap<String, String> map = redisson.getMap("simpleMap");
map.put("mapKey", "This is a map value");
String mapValue = map.get("mapKey");
System.out.println("stored map value: " + mapValue);
// implements java.util.concurrent.locks.Lock
RLock lock = redisson.getLock("simpleLock");
lock.lock();
try {
// do some actions
} finally {
lock.unlock();
}
redisson.shutdown();
}
}
Azure Cache, Amazon ElastiCache, and Google Cloud Memorystore Support
Redisson supports three of the most popular options for fully managed Redis services in the cloud:
- Azure Cache
- Amazon ElastiCache
- Google Cloud Memorystore
To learn more about using Redisson with these Redis cloud services, consult our pages on Azure Cache and AWS ElastiCache.
Redisson Vs. Jedis
Redisson isn't the only Java client library for Redis. So how does Redisson compare with other Redis Java clients like Jedis?
For one, Redisson offers a much richer set of distributed collections than Jedis. The list of distributed collections in Redisson consists of:
- Map
- Multimap
- Set
- List
- Queue
- Deque
- SortedSet
- ScoredSortedSet
- PriorityQueue
- PriorityDeque
- DelayedQueue
- Stream
- RingBuffer
Jedis, on the other hand, only supports the following distributed collections with plain commands:
- Map
- Multimap
- Set
- List
- Queue
- Deque
- Stream
- ScoredSortedSet
Distributed collections such as PriorityQueues
, PriorityDeques
, DelayedQueues
, Streams
, and RingBuffers
are not available in Jedis at all. In addition, Jedis does not support distributed locks and synchronizers such as Locks
, Semaphores
, and CountDownLatches
, or distributed services such as RemoteService
and LiveObjectService
.
Redisson also outperforms Jedis when it comes to features like advanced cache support, transactions, API architectures, and custom data serialization. To read a full comparison between Redisson and Jedis, check out our page Feature Comparison: Redisson vs. Jedis.
Further Reading
Opinions expressed by DZone contributors are their own.
Comments