/red-utils

Distributed Lock Implementation With Redis

Primary LanguageJavaApache License 2.0Apache-2.0

RedUtils

Distributed Lock Implementation With Redis

license Build Status

Note

For reading the idea and the algorithm behind this, please visit https://dzone.com/articles/distributed-lock-implementation-with-redis

Introduction

RedUtils is a distributed lock and using Redis for storing and expiring locks. It has the following features:

  • Leased-Based Lock: If any clients crash or restarted abnormally, eventually lock will be free.
  • Safe: Provided that fsync=always on every Redis instance we have safety even if Redis become unavailable after getting lock.
  • Auto-Refreshing Lock: A lock that is acquired by the client can be held as long as the client is alive, and the connection is OK.

Getting Started

Requirements

Install Redis or use the following command if you have Docker installed

docker run --name some-redis  -e ALLOW_EMPTY_PASSWORD=yes -p 6379:6379 --rm -it redis

Add the following dependency (Java 8 is required)

<dependency>
    <groupId>com.github.siahsang</groupId>
    <artifactId>red-utils</artifactId>
    <version>1.0.4</version>
</dependency>

How to use it?

Getting the lock with the default configuration. Wait for getting the lock if it is acquired by another thread.

RedUtilsLock redUtilsLock = new RedUtilsLockImpl();
redUtilsLock.acquire("lock1", () -> {
    // some operation
});

Try to acquire the lock and return true after executing the operation, otherwise, return false immediately.

RedUtilsLock redUtilsLock = new RedUtilsLockImpl();
boolean getLockSuccessfully = redUtilsLock.tryAcquire("lock1", () -> {
    // some operation
});

You can also provide configuration when initializing RedUtilsLock

RedUtilsConfig redUtilsConfig = new RedUtilsConfig.RedUtilsConfigBuilder()
            .hostAddress("127.0.0.1")
            .port("6379")
            .replicaCount(3)
            .leaseTimeMillis(40_000)
            .build();

RedUtilsLock redUtilsLock = new RedUtilsLockImpl(redUtilsConfig);

To see more examples please see the tests

Running the tests

For running the tests, you should install Docker(test cases use testcontainer for running Redis). After that you can run all tests with:

mvn clean test

Caveats

There are some caveats that you should be aware of:

  1. I assume clocks are synchronized between different nodes.
  2. I assume there aren't any long thread pause or process pause after getting lock but before using it.
  3. To achieve strong consistency you should enable the option fsync=always on every Redis instance.
  4. In current implementation, locks is not fair; for example, a client may wait a long time to get the lock and at the same time another client get the lock immediately.

Dependencies

  • Jedis
  • Slf4j