When it comes to Redis locks, these three are probably the most frequently mentioned terms:
- Setnx
- Redlock
- Redisson
Setnx
Actually, what people usually call the Setnx command doesn’t only mean Redis’s setnx key value command.
It generally refers to using Redis’s set command with the nx parameter added. The set command now already supports all these optional parameters:
SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
Of course, I won’t recite the API in this article. If any of the basic parameters are still unclear, you can hop over to the official site: https://redis.io/commands/set

The figure above is my rough sketch of how Setnx works. It mainly relies on the property that the set only succeeds when the key doesn’t exist: once process A holds the lock, as long as the lock’s key hasn’t been deleted, process B will naturally fail to acquire it.
So why use PX 30000 to set a timeout?
It’s because you’re afraid process A won’t play fair — if it crashes before the lock is released, it takes the lock with it, and then nobody in the system can get it.
Even so, you still can’t guarantee it’s foolproof.
If process A misbehaves again and operates on the resources inside the lock for longer than the timeout I set, other processes will end up acquiring the lock; and when process A comes back, it turns around and deletes the other process’s lock, as shown in the figure:

Same figure as before, except that at time T5 the lock times out and gets released by Redis.
Process B happily acquires the lock at T6, and shortly afterwards process A finishes its work, turns around, does a del — and releases the lock.
When process B finishes and goes to release the lock (time T8 in the figure):
Not finding the lock is actually the good outcome; if at time T7 a process C comes along and successfully acquires the lock, then process B releases process C’s lock.
And so on — process C may release process D’s lock, process D… (no nesting dolls allowed), and what exactly comes of it is anyone’s guess.
So when using Setnx, although the key does the main work, the value shouldn’t sit idle either — you can set a unique client ID, or use a random value such as a UUID.
When unlocking, first fetch the value to check whether the lock was added by the current process, and only then delete it. Pseudocode:
String uuid = xxxx;
// Pseudocode; the concrete implementation depends on the connection tool used in the project
// Some provide a method named set, others call it setIfAbsent
set Test uuid NX PX 3000
try{
// biz handle....
} finally {
// unlock
if(uuid.equals(redisTool.get('Test')){
redisTool.del('Test');
}
}
Now that looks solid, doesn’t it.
On the contrary, this time the problem is even more obvious: inside the finally block, get and del are not atomic operations, so there are still process safety issues.
Why go on about it if it’s problematic?
First, you have to understand where the weaknesses are before you can improve things.
Second, lots of companies are in fact still using that last piece of code above.
The big project / small project paradox: big companies implement the standards, while small companies and small projects are less rigorous, but they don’t have much concurrency either, so the probability of something going wrong is as low as it is at a big company. ——Lu Xun
So one of the correct ways to delete a lock is to use a Lua script, run through Redis’s eval/evalsha command:
-- Lua delete lock:
-- KEYS and ARGV are the parameters passed in as sets, corresponding to Test and uuid above.
-- If the corresponding value equals the uuid passed in.
if redis.call('get', KEYS[1]) == ARGV[1]
then
-- perform the delete operation
return redis.call('del', KEYS[1])
else
-- not successful, return 0
return 0
end
Put plainly, the reason a Lua script guarantees atomicity is this:
No matter how fancy the Lua you write, it is executed as a single command (eval/evalsha); until that one command finishes, other clients can’t see it.
So given how much trouble that is, is there a better tool? That brings us to Redisson.
Before introducing Redisson, let me briefly explain why Setnx nowadays by default means the set command with the nx parameter, rather than the Setnx command itself.
Because before Redis 2.6.12, set didn’t support the nx parameter, so creating a lock required two commands:
1. setnx Test uuid
2. expire Test 30
That is, putting in the key and setting the expiry are two separate steps, and in theory step 1 could finish and then the program crash, so atomicity can’t be guaranteed.
But back in 2013 — seven years ago — Redis released version 2.6.12, and the official site (the set command page [1]) had long since stated that “SETNX, SETEX, PSETEX may be deprecated and permanently removed in future versions”.
I once read an article by a big shot that included a little interview trick for guiding beginners. I forget the exact wording, but it went roughly like this:
When talking about Redis locks, you can start with Setnx and then gradually lead into how the set command can take parameters — that shows off your breadth of knowledge.
If you happen to have read that article too and learned this trick, as the author of this article I’d like to add one reminder:
Pay attention to your years of work experience! If you first answer with a command the official site says is about to be deprecated, and then bring up a “new feature” of the set command from seven years ago, an interviewer will think they’ve traveled back in time if someone who just graduated says this.
You trick the interviewer, and the interviewer tricks you. ——vt・Wozijishuode (a pun on “as I myself said”)
Redisson
Redisson is one of the Java clients for Redis, providing APIs that make operating Redis convenient.
But this Redisson client is quite something. Here’s a screenshot I took of just part of the feature list on the official site:

The feature list is honestly far too long. Do you also see some class names from the JUC package in there? Redisson made distributed versions for us — for example, with AtomicLong you can just use RedissonAtomicLong directly; you don’t even have to memorize a new class name. Very user-friendly.
Locks are just the tip of its iceberg, and as you can see from its wiki [2] page, it supports master-slave, sentinel, cluster and other modes; and of course single-node mode is definitely supported.
This article is still focused on locks, so I won’t cover the rest in detail.
The source of Redisson’s ordinary lock implementation is mainly the RedissonLock class; if you haven’t looked at its source yet, it’s worth a look.
In the source, both locking and unlocking are done with Lua scripts, packaged very thoroughly and ready to use out of the box.
There’s a small detail here: locking can be done with Setnx alone, so isn’t using a Lua script redundant? I thought about it quite rigorously: how could something this impressive contain useless code?
Actually, I looked carefully and the Lua scripts for locking and unlocking are very thorough, including lock reentrancy — that really is remarkably well thought out. I also wrote some code on the spot to test it:

It really is as smooth to use as the JDK’s ReentrantLock. So if Redisson’s implementation is already this complete, what is RedLock?
RedLock
The Chinese name for RedLock is a direct translation — it’s simply called the red lock.
The red lock isn’t a tool, but a distributed locking algorithm proposed by the Redis team.
In the Redisson we just covered, a redLock version of the lock is actually implemented. That is, besides the getLock method, there’s also a getRedLock method.
Here’s a rough sketch of my understanding of the red lock:

If you’re not familiar with Redis high-availability deployments, that’s fine. Although the RedLock algorithm requires multiple instances, those instances are all deployed independently, with no master-slave relationship.
The author of RedLock points out that the reason for using independent instances is to avoid lock loss caused by Redis asynchronous replication — for example, the master node dying before it manages to pass the data it just set to the slave node.
Some people probably think these big shots are just argumentative, always obsessing over extreme cases. But that’s high availability for you — what you’re competing over is the digits after the decimal point in 99.999…%.
Back to that crude figure above: the red lock algorithm holds that as long as (N/2) + 1 nodes successfully lock, the lock is considered acquired, and when unlocking, all instances are unlocked. The process is:
Request a lock from the five nodes in sequence
Decide whether to skip a node based on a certain timeout
Three nodes lock successfully and the time taken is less than the lock’s validity period
The lock is considered acquired
That is, if the lock expires after 30 seconds and locking three nodes takes 31 seconds, then of course the lock acquisition fails.
This is just an example; in practice you shouldn’t wait that long for each node. As the official site says, if the validity period is 10 seconds, then the operation timeout for a single Redis instance should be between 5 and 50 milliseconds (mind the units).
Still assuming we set the validity period to 30 seconds, and two Redis nodes timed out in the figure. Then the nodes that locked successfully took 3 seconds in total, so the lock’s actual validity period is less than 27 seconds.
That is, you subtract the 3 seconds for the three instances that locked successfully, and you also subtract the total time spent waiting for the timed-out Redis instances.
Reading this, you may have some doubts about the algorithm — and you’re not alone.
Take another look at the Redis official site’s description of the red lock [3].
Right at the bottom of that page you’ll find the famous “gods fighting” episode about the red lock.
Namely the RedLock debate between Martin Kleppmann and Antirez. One is a very seasoned distributed systems architect, the other is the father of Redis.
Getting publicly called out by the official site is the deadliest of all.
Just kidding — if a challenge gets posted on the official site, it clearly has value.
So if you’re going to use the red lock in a project, besides reading the introduction to it, you might want to read two more articles, namely:
Martin Kleppmann’s critique: http://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
Antirez’s rebuttal: http://antirez.com/news/101
Summary
After all this, have you noticed that no matter how you implement it, you can’t guarantee 100% stability.
That’s just how programs are — nothing is absolutely stable, so doing a good job on the manual compensation step is also important. After all: when the tech isn’t enough, humans make up the difference ~
Related links:
https://github.com/redisson/redisson/wiki/Table-of-Content
https://redis.io/topics/distlock
Original article: https://juejin.cn/post/6844904082860146695

