Java Remote Method Invocation with Redisson
This article shows how you can use a Redis-based in-memory data grid for Java remote method invocations.
Join the DZone community and get the full member experience.
Join For FreeOverview
Remote methods invocations are always been a hot topic for discussion in the Java world. What can Redisson - Redis based In-Memory Data Grid for Java have to offer to solve this task?
Usually remote method invocation implies the existence of a client side (invokes remote method) and server side (executes remote method). In Redisson both Java client and server sides connected to each other through Redis server.
Let's assume YourServiceImpl class contains a method you need to invoke remotely and implements YourService interface.
YourServiceImpl object should be registered in Redisson via RRemoteService object:
YourService yourService = new YourServiceImpl();
RRemoteService remoteService = redisson.getRemoteService();
remoteService.register(YourService.class, yourService);
The service can be registered:
On a different node.
Or in a different JVM on the same node with an independent client-side Redisson instance.
Or even on the same JVM with a shared client-side Redisson instance.
To invoke Java methods remotely, only the service interface is required:
RRemoteService remoteService = redisson.getRemoteService();
YourService service = remoteService.get(YourService.class);
MyObject result = service.myMethod(someParam1, someParam2);
A method can be invoked: (use the same illustrations as above)
From a different node.
Or another JVM on same node with server side Redisson instance.
Or even from same JVM sharding server side Redisson instance.
Services implementations need to be POJOs, method parameters, and result object type can literally be anything. There is no limit to the amount of client side and/or server side instances.
Java Remote invocations are stored in Redis queue and executes in parallel mode if more than one server-side workers are available.
The number of server side workers for each service is defined during registration:
RRemoteService remoteService = redisson.getRemoteService();
// can handle only 1 invocation concurrently
remoteService.register(YourService.class, yourService);
// able to handle up to 12 invocations concurrently
remoteService.register(SomeServiceInterface.class, someServiceImpl, 12);
The total number of parallel executors can be calculated as follows:
W = R1 + R2 + R3 + ... + Rn
W - total available parallel executors (workers).
R1 - executors amount defined during service registration on the first Redisson instance.
R2 - executors amount defined during service registration on the second Redisson instance.
R3 - executors amount defined during service registration on the third Redisson instance.
Rn - executors amount defined during service registration on the Nth Redisson instance.
Commands exceeding this W-number of free executors will be queued for the next available executor. Remote invocations execute in sequential mode if there is only 1 workers are available.
Invocation Options
There are twos timeout that can be defined during Java Remote invocation: ack-timeout and result-timeout.
Ack-timeout is used to determine if the method executor has received a request.
RemoteService offers a few options for each remote invocation via the org.redisson.core.RemoteInvocationOptions object. These options provide a way of changing timeouts; they can also be used to skip ack-response and/or result-response. Examples:
// 1 second ack timeout and 30 seconds execution timeout
RemoteInvocationOptions options = RemoteInvocationOptions.defaults();
// no ack but 30 seconds execution timeout
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck();
// 1 second ack timeout then forget the result
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noResult();
// 1 minute ack timeout then forget about the result
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().expectAckWithin(1, TimeUnit.MINUTES).noResult();
// no ack and forget about the result (fire and forget)
RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck().noResult();
RRemoteService remoteService = redisson.getRemoteService();
YourService service = remoteService.get(YourService.class, options);
Asynchronous Calls
Java Remote invocations can be made in an asynchronous manner via a separate interface marked with the @RRemoteAsync annotation. The method signature needs to be the same as the corresponding method in the remote interface. Each method should return the org.redisson.core.RFuture object, which extends java.util.concurrent.Future and java.util.concurrent.CompletionStage interfaces. The latter provides a few useful methods. Asynchronous interface validation will be performed during the RRemoteService.get method invocation. It's not necessary to define all of the original methods, only those which need to be called in an asynchronous manner.
public interface YourService {
Long someMethod1(Long param1, String param2);
void someMethod2(MyObject param);
MyObject someMethod3();
}
// async interface for YourService
@RRemoteAsync(YourService.class)
public interface YourServiceAsync {
RFuture<Long> someMethod1(Long param1, String param2);
RFuture<Void> someMethod2(MyObject param);
}
RRemoteService remoteService = redisson.getRemoteService();
YourServiceAsync asyncService = remoteService.get(YourServiceAsync.class);
RFuture<Long> res = asyncService.someMethod1(12L, "param");
res.thenApply(r -> {
...
});
Data Serialization
Redisson uses codec to serialize Java arguments and result objects transfered during method invocation and stored in Redis. Many popular codecs are available for usage:
Codec class name |
Description |
org.redisson.codec.JsonJacksonCodec |
Jackson JSON codec |
org.redisson.codec.CborJacksonCodec |
CBOR binary json codec |
org.redisson.codec.MsgPackJacksonCodec |
MsgPack binary json codec |
org.redisson.codec.KryoCodec |
Kryo binary codec |
org.redisson.codec.SerializationCodec |
JDK Serialization codec |
org.redisson.codec.FstCodec |
FST codec |
org.redisson.codec.LZ4Codec |
LZ4 compression codec |
org.redisson.codec.SnappyCodec |
Snappy compression codec |
Opinions expressed by DZone contributors are their own.
Comments