Redis Distributed Locks: SETNX, Lua Scripts, Redisson & Redlock Algorithm
This article explains four approaches to implementing distributed locks with Redis: basic SETNX with expiration, atomic Lua scripts for lock acquire/release, the Redisson Java client with watchdog renewal, and the Redlock algorithm for high-availability multi-master deployments.
In distributed systems, controlling access to shared resources requires distributed locks. Unlike single-process locks using synchronized, distributed deployments need coordination across nodes. A typical scenario: a Spring Quartz scheduled task runs on multiple cluster nodes simultaneously, causing duplicate processing unless a distributed lock ensures only one executes.
1. Using SETNX Command
SETNX key valuesets a key only if it does not exist, returning 1 on success (lock acquired) or 0 on failure. To prevent deadlocks, an expiration must be set via EXPIRE, but these two commands are not atomic: if the process crashes after SETNX but before EXPIRE, the key never expires and other threads cannot acquire the lock.
Since Redis 2.6.12, SETNX is deprecated. The atomic replacement is:
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds] NX: set only if key does not exist XX: set only if key exists EX: expire in seconds PX: expire in milliseconds SET ... NX EX is atomic, but using DEL to release the lock risks deleting another client's lock if the original lock expired and a new one was acquired.
2. Using Lua Scripts for Atomicity
Lua scripts execute atomically via EVAL. The lock script checks SETNX and sets expiry in one step:
if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then
redis.call('expire',KEYS[1],ARGV[2])
return 1
else
return 0
end;Unlock script verifies ownership before deletion:
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end;A complete Java example ( RedisDistributeLock) wraps these scripts, taking a RedisClient, lock key, unique client value, and expiry time in milliseconds. The lock() method calls eval with the lock script; unlock() calls eval with the unlock script. Usage:
RedisDistributeLock lock = new RedisDistributeLock(jedis, "mylock", "myclient", 2000);
if (lock.lock()) {
try { System.out.println("Lock acquired!"); }
finally { lock.unlock(); }
}3. Using Redisson Client
Redisson (version 3.35.0) provides high-level distributed locks with automatic lease renewal (watchdog). Maven dependency:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.35.0</version>
</dependency>Spring configuration creates a RedissonClient bean pointing to redis://127.0.0.1:6379. Acquiring a lock:
RLock lock = redissonClient.getLock("fullstack_lock");
try {
lock.tryLock(3, 30, TimeUnit.SECONDS);
System.out.println("Lock acquired!");
} finally {
lock.unlock();
}Internally, Redisson executes Lua scripts and runs a background watchdog thread that extends the lock TTL while the holder is alive, preventing premature expiry during long operations.
4. Redlock Algorithm for High Availability
In master-slave replication, if the master fails after a client acquires the lock but before replication completes, the promoted slave lacks the lock key, allowing another client to acquire it — violating mutual exclusion.
Antirez proposed Redlock: deploy N independent Redis masters (no replication). Steps:
Record start time in milliseconds.
Sequentially attempt lock on each instance with same key/value; timeout per instance must be far less than total lock TTL (e.g., 5–50 ms vs 10 s) to avoid blocking on down nodes.
Lock succeeds only if majority (N/2+1) instances acquire it AND total elapsed time < lock TTL.
Effective TTL = initial TTL − elapsed time.
On failure (insufficient majority or timeout), send unlock to all instances.
Redlock's safety was debated by Martin Kleppmann; see Redis official site for details.
5. Summary
Redis offers multiple distributed lock patterns: simple SET NX EX for basic cases, Lua scripts for atomic check-and-set, Redisson for production-ready features (watchdog, fair locks, pub/sub), and Redlock for high-availability requirements. For systems demanding strong consistency (CP), ZooKeeper or etcd may be preferable over Redis (CA).
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
