In this guide we will create a remote key-value storage using RPC module.
App will have 2 basic operations: put and get and will use RPC as the communication protocol.
When writing distributed application the common concern is what protocol to use for communication. There are two main
While HTTP is more popular and well-specified, it has some overhead. When performance is a significant aspect of application,
you should use something faster than HTTP. And for this purpose DataKernel framework has an RPC module which is based on
fast serializers and custom optimized communication protocol that allows to significantly improve application performance.
First, create a folder for application and build an appropriate project structure:
Next, configure your pom.xml file like this:
2. Define basic app functionality
Since we have two basic operations to implement (put and get), let’s start with writing down classes that will be used for
communication between the client and the server: specifically, PutRequest, PutResponse, GetRequest and GetResponse.
Instances of these classes will be serialized by using the fast DataKernel Serializer. It requires some meta information
about these classes, which is provided by appropriate annotations. The basic rules are:
Use @Serialize annotation with an order number on the getter of property. Ordering provides better compatibility in case
classes are changed.
Use @Deserialize annotation with a property name (which should be the same as the one in the getter) in constructor.
Use @SerializeNullable on properties that can have null values.
Therefore, classes for communication should look like following:
Next, let’s write a simple implementation of key-value storage:
3. Create client and server
Now, let’s write down an AbstractModule for the RPC server using DataKernel Boot to handle the “get” and “put” requests
As you can see, in order to properly create an RpcServer we should indicate all classes that will be sent between a
client and a server, and specify appropriate RequestHandler for each request class.
We represent them as the third arguments in these lines using Java 1.8 lambdas.
Next, create a launcher for the RPC server:
Now, let’s write the RPC client. In order to create the it we should again indicate all classes that will be used
for communication and specify RpcStrategy. There is a whole bunch of strategies in the RPC module (such as single-server,
first-available, round-robin, sharding and so on). The nice thing about them is that all strategies can be combined. For
example, if you want to dispatch requests between 2 shards, and each shard actually contains main and reserve servers,
you can easily tell RPC client to dispatch requests in a proper way using the following code:
But since we only have one server, we will just use the single-server strategy:
Let’s also build ClientLauncher. In run() we will consider command line arguments and make appropriate requests
As you can see, sendRequest() method returns a CompletionStage, at which we could listen for its results asynchronously
Congratulations! We’ve finished writing the code for this app.
First, launch server.
Open ServerLauncher class and run its main() method.
Then make a “put” request.
Open ClientLauncher class which is located at datakernel -> examples -> remote-key-value-storage
and set up program arguments to --put key1 value1. For IntelliJ IDEA: Run -> Edit configurations ->
|Run/Debug Configurations -> |Program arguments -> --put key1 value1||. Then run launcher’s main() method.
You will see the following output:
Finally, make a “get” request.
Open ClientLauncher class again and set up program arguments to --get key1. For IntelliJ IDEA: Run ->
Edit configurations -> |Run/Debug Configurations -> |Program arguments -> --get key1||. Then run main() method of the
You will see the following output:
Congratulations, you’ve just created a remote key-value storage with RPC communication protocol!