Metaparticle/Sync for Java is a library that implements distributed synchronization for cloud-native applications using a container side-car and Kubernetes primitives.
Metaparticle/Sync for Java can be used for locking or for leader election
To add the io.metaparticle.sync library to your code you need to do two things:
- Import the library:
import io.metaparticle.sync.*; - Run the
electorside-car container. This is typically done via a Kubernetes Deployment (see examples below)
The simplest usage is to deploy mutual exclusion locks between different distributed components
Here's the code for a simple locking example, that locks a lock named test and holds it for 45 seconds.
import io.metaparticle.sync.Lock;
public class Main {
public static void main(String[] args) throws InterruptedException {
Lock lock = new Lock("test");
System.out.println("Locking.");
lock.lock();
System.out.println("Sleeping.");
Thread.sleep(45 * 1000);
System.out.println("Unlocking.");
lock.unlock();
}
}You'll notice that a lock requires a name. This name should be unique for a cluster.
Simply creating a lock doesn't cause mutual exclusion. You also need to call lock.lock(). When
you are done, you call lock.unlock() to release the lock. Locks have a TTL (time to live) so
in the event of a failure, the lock will also be eventually lost.
Locks implement the java.util.concurrent.Lock interface and are thus compatible with locks any
where in a Java program.
To deploy code using the io.metaparticle.sync package, you need to also include a side-car that
does the heavy lifting for the lock. Your code and the sidecar should both be package as containers
and then deployed as a Kubernetes Pod.
Here is an example Kubernetes deployment:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
run: lock-java
name: lock-java
namespace: default
spec:
replicas: 2
selector:
matchLabels:
run: lock-java
template:
metadata:
labels:
run: lock-java
spec:
containers:
- image: brendanburns/elector
name: elector
- image: brendanburns/sync-java
name: exampleYou can create this with kubectl create -f lock-deploy.yaml which will create two different Pods, both of which are trying to obtain a lock named test.
An extension of locking is leader election where a leader is chosen from a group of replicas. This leader remains the leader for as long as it is healthy. If the leader ever fails, a new leader is chosen. This is an extremely useful pattern for implementing a variety of distributed systems. Generally leader election is performed for a named shard which represents some piece of data to be owned/maintained by the leader.
Implementing leader election in io.metaparticle.sync is simple, here is code that performs
leader election for a shard named test.
import io.metaparticle.sync.Election;
public class ElectionMain {
public static void main(String[] args) throws InterruptedException {
Election e = new Election("test");
e.addMasterListener(() -> {
System.out.println("I am the master.");
// <-- Do something as master here -->
});
e.addMasterLostListener(() -> {
System.out.println("I lost the master.");
// <-- Handle losing the master here -->
});
}As with locking, you need to deploy the elector side-car to take advantage of io.metaparticle.sync elections. Here's an example Kubernetes Deployment which deploys three leader replicas:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
run: elector-java
name: elector-java
namespace: default
spec:
replicas: 3
selector:
matchLabels:
run: elector-java
template:
metadata:
labels:
run: elector-java
spec:
containers:
- image: brendanburns/elector
name: elector
# Replace the container below with your container.
- image: brendanburns/sync-java
name: example
command:
- java
- -classpath
- /main.jar
- io.metaparticle.sync.examples.ElectionMainIf you are interested in the technical details of how this all works, please see the overview.