Distributed Lock With Redis

There are many ways to implement a distributed lock in a clustered environment, most common is using database (most databases have locks or atomic operation support built in) or zookeeper as the shared resource. My problem was that we didn’t want to set zookeeper cluster just for this and I didn’t want to implement it on our sql server because the plan was to switch to another DB solution in the future. Another good solution which I used in the past is DynamoDB Conditional writes feature, but management preferred not to add another dependency in AWS since their costs were too high. We did though  had Redis for caching, and Redis support locking keys with setnx. I have  found Redisson, which is a very cool java open source Redis client which implement Redis Lock. We have tested it on our lab and its run on our production servers  – and so far so good… This is how we have done it: we have the distributed locker interface ( because as we know life tomorrow we I’ll need to switch to another lock solution 🙂 )

public interface DistributedLocker {

public <T> T lock(String resourceName,
AquiredLockWorker<T> worker) throws UnableToAquireLockException, Exception;

public <T> T lock(String resourceName,
AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception;

}
public interface AquiredLockWorker<T> {
public T invokeAfterLockAquire() throws Exception;
}

and this is the Locker implementation using Redisson:

@Component
public class RedisLocker implements DistributedLocker{

private final static String LOCKER_PREFIX = "lock:";

@Autowired
private RedissonConnector rdsConnector;

@Override
public <T> T lock(String resourceName, AquiredLockWorker<T> worker)
throws InterruptedException, UnableToAquireLockException, Exception {

return lock(resourceName, worker, 100);
}

@Override
public <T> T lock(String resourceName, AquiredLockWorker<T> worker,
int lockTime) throws UnableToAquireLockException,
Exception {
RedissonClient redisson = rdsConnector.getClient();

RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);

// Wait for 100 seconds seconds and automatically unlock it after lockTime seconds
boolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);;
if (success) {
try {
return worker.invokeAfterLockAquire();
} finally {
lock.unlock();
}
}
throw new UnableToAquireLockException();
}
}

 

I hope it helped someone.

Yair

 

Advertisements