2. Integration
with
frameworks
LockDistributed
locks and
synchronizers ReadWriteLock RedLockSemaphore
Distributed
collections
… MultiLockFairLock
Map
Set
Multimap
List
Queue
Deque
SortedSet
DelayedQueue
RemoteService
Distributed
services LiveObjectService
ExecutorService
SchedulerService
MapReduce
Service
…
REDISSON OVERVIEW
Spring
Hibernate cache
JCache API
(JSR-107)
Tomcat
Dropwizard metrics
3. MAP
ConcurrentMap<Integer, MyObject> map = new ConcurrentHashMap<>();
map.put(20, new MyObject("oldobj"));
map.putIfAbsent(20, new MyObject("newobj"));
map.containsKey(1);
7. REDISSON MAP
WITH LOCAL CACHE
ConcurrentMap<Integer, MyObject> map =
redisson.getLocalCachedMap("someMap");
Read operations are executed about 100x faster
8. LOCAL CACHED MAP
ENTRY EVICTION POLICY
▸Least Recently Used
▸Least Frequently Used
▸Soft Reference
▸Weak Reference
9. LOCAL CACHED MAP
ENTRY INVALIDATION POLICY
▸On change
▸On change
+ clears whole cache on reconnect
▸On change
+ clears changed entries only on reconnect
19. MAPREDUCE
DATA SOURCE EXAMPLE
RMap<String, String> map = redisson.getMap("wordsMap");
map.put(“page1:line1", "Alice was beginning to get very tired");
map.put("page1:line2", "of sitting by her sister on the bank and");
map.put("page1:line3", "of having nothing to do once or twice she");
map.put("page1:line4", "had peeked into the book her sister was reading");
map.put("page1:line5", "but it had no pictures or conversations in it");
map.put("page1:line6", "and what is the use of a book");
map.put("page1:line7", "thought Alice without pictures or conversation");
20. MAPPER DEFINITION
public class WordMapper implements
RMapper<String, String, String, Integer> {
@Override
public void map(String key, String value,
RCollector<String, Integer> collector) {
String[] words = value.split(" ");
for (String word : words) {
collector.emit(word, 1);
}
}
}
21. REDUCER DEFINITION
public class WordReducer implements RReducer<String, Integer> {
@Override
public Integer reduce(String word, Iterator<Integer> iter) {
int sum = 0;
while (iter.hasNext()) {
Integer i = (Integer) iter.next();
sum += i;
}
return sum;
}
}
22. COLLATOR DEFINITION
public class WordCollator implements RCollator<String, Integer, Integer> {
@Override
public Integer collate(Map<String, Integer> result) {
int totalWordsAmount = 0;
for (Integer count : result.values()) {
totalWordsAmount += count;
}
return totalWordsAmount;
}
}
23. RUNNING MAPREDUCE
RMap<String, String> map = redisson.getMap("wordsMap");
RMapReduce mapReduce = map.mapReduce()
.mapper(new WordMapper())
.reducer(new WordReducer())
.timeout(60, TimeUnit.SECONDS);
// count occurrences of words
Map<String, Integer> wordToNumber = mapReduce.execute();
// count total words amount
Integer totalWordsAmount = mapReduce.execute(new WordCollator());
24. REDISSON VS
OTHER IMDG OR CACHE SOLUTION
Redisson
+ Redis
Java based IMDG
or cache solution
(hazelcast, ehcache …)
Distributed objects
and services
Large memory
amount handling have issues
Fully-managed
service support
Hi, my name is Nikita. I’m a founder of Redisson project. And I would like to give you brief overview of Java map structures and services with Redisson
Redisson is a Redis based Data Grid which offers you all necessary things required to create distributed application on Java.
It offers distributed locks and synchronizers: FairLock, ReadWriteLock, Semaphore, RedLock, MultiLock.
Distributed collections: Map, Multimap, Queues, SortedSet and many more.
Distributed services and provides integration with frameworks like Spring, Hibernate, Tomcat and also implements JCache API
We will have a look more closely at Map structures, Executor, Scheduler and MapReduce services.
Map is most popular data structure in Java and here is a typical usage of map:
If you want to change you code to achieve the same with a Redis hash, the only changes you should do is to create the map using Redisson.
Redisson maps methods directly to Redis commands. In this example “put” method implemented using HSET command.
But putIfAbsent method implemented using lua script.
Redisson heavily relies on lua scripts. Because lua script is fast, executes atomically and allows to create complex execution flow.
This lua script uses only two Redis commands inside.
Redisson provides sharded version of Map structure.
This object splitted to multiple shards. Shards amount is configurable.
If Redisson connected to Redis Cluster each Redis node will get approximately equal amount of shards if Redis nodes have equal amount of slots.
Another map implementation provided by Redisson is LocalCachedMap object. This object maintains the local cache or so called near cache.
This type of map structure is very useful in cases when map used mainly for read operations or network round trips is undesirable.
Read operations with local cache are executed about 100 times faster in comparison with usual map.
Since map stored in Redis it could have enormous amount of entries. So, eviction policy could be applied for local cache. Few options are available:
Least Recently Used, Least Frequently Used eviction policies which are well known. Soft and Weak reference policies evicts map entries during garbage collection process.
In distributed application any amount of Local Cached Map instances may be used and data could be change through each of them.
To maintain actual data in local cache Redisson offers invalidation policies:
On change policy invalidates corresponding Local Cache entry across all instances if it has changed in Redis. This algorithm implemented using publish subscribe. Each of Local Cached Map instances subscribes to common channel and listen for message which always published if map entry has changed. So, corresponding map entry is deleted from local cache during invalidation message handling.
Next policy is the same as the first one, but also clears cache in case of any reconnection to Redis.
And the last policy also maintains map entry changes log. With last policy each time when map entry has changed Redisson does two things:
Publishes message to common channel and makes a log record about entry change. These invalidation log records are loaded each time once the connection to Redis has been reconnected.
Invalidation log records are stored for last 10 minutes by default. In this way log won’t grow continuously.
Let’s move to tasks execution.
Redisson has two parts: Redisson client itself and Redisson Node used for tasks running. Redisson client run on application side. Redisson Node run in standalone mode. Each Redisson Node has configurable amount of workers.
Workers are used to execute tasks submitted through Redisson client. All Redisson Nodes are stateless and tasks are stored in Redis until the moment of execution. And of course Redisson Nodes require some actions to deploy, run and maintain. In some cases it would be nice to have workers right on application side.
Redisson allows to do it with single line of code.
Some Redisson users run more than thousand instances of Redisson in production and therefore such approach could be quite effective in terms of computing power utilization.
Let’s consider code examples. Redisson uses standard Runnable and Callable interfaces to define tasks.
Each task may have own fields to define parameters during task submission. RedissonClient instance will be injected automatically if field has RedissonClient type and marked with RInject annotation. This provides access to all Redisson’s objects.
Same rules applied to Runnable task
It's pretty easy to submit a task since Redisson service already implements familiar ExecutorService interface from java.util.concurrent package.
Each task could have any amount of parameters passed through task’s constructor or setter methods.
Scheduled tasks are submitted using scheduler service which implements ScheduledExecutorService interface from java.util.concurrent package.
Tasks could be scheduled for one time execution or scheduled for multiple executions with defined fixed rate or fixed delay between each execution.
Tasks scheduler service allows developer to define more complex scheduling using cron expressions. They fully compatible with Quartz cron format.
The next major feature is a MapReduce framework. It is used to process large amount of data across many Redisson Node.
Redisson offers MapReduce support for various objects like Set, Map, SortedSet, List and many more.
Map and reduce phases are main parts of MapReduce framework. If you use SharedMap or ShardedSet as data source.
Then map phase will be splitted into many subtasks and running in parallel. In this case each subtask works only with own part of map or set.
For other objects Map phase is always executed as a single task.
Reduce phase is always run in parallel because intermediate values produced during map phase are stored in sharded store which passed to Reduce tasks.
Let’s consider an example how to count words amount in a book using MapReduce.
First we need to populate collection with data. In our example we will use Map
and a few first lines from the first chapter of “Alice in wonderland” book.
Before MapReduce execution we should define two objects: Mapper and Reducer.
Mapper object is used to produce intermediate values and store them into Redis using Collector object.
This mapper example applied to each Map entry and split value by space to separate words.
Reducer object handles intermediate values produced during map phase.
In our example it’s a word itself and word occurrences amount collection. This Reducer example calculates the total sum for each word.
Collator object is an optional object and used only when result of MapReduce process should be a single object. In our case it’s a total amount of words.
This code example shows how to run mapreduce task with objects provided on previous slides.
Each collection object has `mapReduce` method which exposes API for mapper, reducer and timeout definition.
Execute methods are used to run Map Reduce process itself.
How does Redisson compare with other in-memory data grids or cache solutions.
Some users has successfully moved away from such products like Hazelcast and ehcache.
Because of few reasons:
Correct large memory amount handling (we all know that Redis can manage with hundreds of gigabytes of RAM on single machine)
Availability of fully managed services like AWS Elasticache, Azure Cache and so on.
Such services offers full automation, support and management of Redis, so developers can focus on their applications and not maintaining their databases.