Kume is a lightweight clustering framework for Java 8. It uses Netty for networking and Kryo for serialization. It's quite easy to start a node in a cluster:
Cluster cluster = new ClusterBuilder()
.services(services)
.members(members)
.serverAddress(serverAddress)
.start();
By default, nodes can discover each other using UDP multicast. However you can set TCP addresses when starting the cluster. Each node sends heartbeat messages to other nodes periodically and when one of the nodes become unreachable you will be notified via MembershipListener interface.
cluster.addMembershipListener(new MembershipListener() {
@Override
public void memberAdded(Member member) {
}
@Override
public void memberRemoved(Member member) {
}
});
You may notice the services parameter when constructing a node on the cluster. The key point of Kume is the services. It simply contains contains your registered services on local node. Services are the abstraction method of Kume. Each service can communicate with other services on the cluster using ServiceContext object which is provided by ServiceInitializer.
public class MyService implements Service {
private final Cluster.ServiceContext bus;
private final CountDownLatch latch;
public MyService(Cluster.ServiceContext bus) {
this.bus = bus;
}
@Override
public void handle(OperationContext ctx, Object msg) {
if(msg.equals(2)) ctx.reply(4);
}
@Override
public void onStart() {
}
@Override
public void onClose() {
}
}
ServiceInitializer services = new ServiceInitializer()
.add((bus) -> new MyService(bus));
Using Cluster.ServiceContext, you can communicate with the other services running on Kume cluster. When you send an object to other node, Kume will serialize the object using Kryo and send the object using Netty TCP sockets. You can handle messages in Service.handle(OperationContext, Object). It's quite similar to Akka's receiver methods.
When you send an object Kume will send the object to the node and forget about it. Therefore we can say that it's a fire-and-forget operation and there is no way to send a message and get a response for the message. If you're requesting something from another node, you can send a Request object tp ServiceContext.send.
serviceContext
.send(Member, (service, ctx) -> ctx.reply(2))
.thenAccept(c -> System.out.println(c));
As you see, you can send lambdas thanks to Kryo's lambda serialization feature and listen for the answer for a spesific request. By default, the timeout for answers are 3 seconds.
You can get service instances from a Cluster object using getService method.
MyService service = cluster.getService(MyService.class);
You can construct almost anything using services. It's the way that you create distributed versions of your data structures. Currently, there are two core services in Kume: RingMap and RaftMasterElection. RingMap is a eventually consistent distributed map implementation and it uses consistent hashing algorithm in order to determine which nodes will own a spesific key of the map. It also uses Riak's vnode algorithm in order to provide a completely fault-tolerant service supports different replication factors of a spesific map. RaftMasterElection is simply a master election service which uses Raft's algorithm.
The documentation is not ready yet and since this is my side project that I plan to use in my analytics project (shameless plug: Rakam), I will eventually complete the first development phase and then start writing a full documentation.
- Write a to-do list.
If you want to contribute the project or suggest an idea feel free to fork it or create a ticket for your suggestion.