1. Introduction
In distributed systems, multiple nodes may access shared resources at the same time, which may lead to data inconsistency. To solve this problem, distributed locks came into being. As a high-performance in-memory database, Redis provides multiple mechanisms to implement distributed locks. This article will introduce in detail how to use Redis to implement distributed locks.
2. Basic concepts of distributed locks
Distributed locking is a locking mechanism spanning multiple processes or nodes to coordinate access to shared resources. It ensures that at any time, only one client can hold the lock, thus avoiding data inconsistency caused by concurrent access.
3. The principle of Redis implementing distributed locks
Redis provides a variety of commands and mechanisms to implement distributed locks. Here are several common implementations:
1. SETNX command
The SETNX (SET if Not eXists) command is used to set the key's value when it does not exist. If the key already exists, the operation fails. This command can be used to implement simple distributed locks. However, the SETNX command itself does not have the function of setting the expiration time, so it needs to be used in conjunction with the EXPIRE command. However, these two commands are not atomic, and if SETNX succeeds but EXPIRE fails, it can lead to deadlocks.
2. Extended parameters of SET command
Redis's SET command supports multiple extended parameters, such as NX (Not eXists), EX (Expire seconds) and PX (Expire milliseconds). Among them, NX and EX/PX can be used in combination to achieve atomic locking operation. For example,SET lock_key unique_lock_value NX EX 10
The command indicates thatlock_key
Set its value tounique_lock_value
, and set the expiration time to 10 seconds.
3. Lua script ensures atomicity
To ensure the atomicity of locking and releasing locks, multiple Redis commands can be packaged into one atomic operation using Lua scripts. For example, a Lua script can be used to implement atomic operations that lock and set expiration time.
4. Steps to implement distributed locks in Redis
1. Introducing Redis dependencies
In Spring Boot projects, you can use it inAdd Redis dependencies to the file to introduce Redis support.
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2. Locking implementation
The lock operation can be implemented using the extended parameters of the SET command or the Lua script. Here is an example of using extended parameters of the SET command to implement locking:
import ; import ; import ; import ; import ; import ; @Component public class RedisLockUtil { @Autowired private StringRedisTemplate redisTemplate; private static final String LOCK_SUCCESS = "OK"; private static final Long RELEASE_SUCCESS = 1L; /** * Try to acquire a distributed lock * * @param lockKey * @param requestId RequestId * @param expireTime Expiry time * @param timeUnit TimeUnit * @return Whether it is successful */ public boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit timeUnit) { String result = ().setIfAbsent(lockKey, requestId, expireTime, timeUnit); return LOCK_SUCCESS.equals(result); } }
3. Release the lock to implement
The release lock operation requires ensuring that only the locks you hold are released to prevent the locks of other clients from being deleted by mistake. This can be achieved by first obtaining the lock's value and then determining whether the value is consistent with its own request identification. To ensure the atomicity of the operation, it can be implemented using Lua scripts.
import ; /** * Release the distributed lock * * @param lockKey * @param requestId RequestId * @return Whether it was released successfully */ public boolean unlock(String lockKey, String requestId) { String script = "if ('get', KEYS[1]) == ARGV[1] then return ('del', KEYS[1]) else return 0 end"; DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); (script); (); return (redisScript, (lockKey), requestId) == RELEASE_SUCCESS; }
4. Set the lock expiration time
When adding a lock, you need to set the expiration time of the lock to prevent the occurrence of deadlock. The expiration time should be set according to the specific business needs, and should not be too long or too short.
5. Code demonstration
1. Introduce dependencies
Make sure to be inRedis dependencies are introduced in the file.
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2. Tools for locking and releasing locks
import ; import ; import ; import ; import ; import ; @Component public class RedisLockUtil { @Autowired private StringRedisTemplate redisTemplate; private static final String LOCK_SUCCESS = "OK"; private static final Long RELEASE_SUCCESS = 1L; /** * Try to acquire a distributed lock * * @param lockKey * @param requestId RequestId * @param expireTime Expiry time * @param timeUnit TimeUnit * @return Whether it is successful */ public boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit timeUnit) { String result = ().setIfAbsent(lockKey, requestId, expireTime, timeUnit); return LOCK_SUCCESS.equals(result); } /** * Release the distributed lock * * @param lockKey * @param requestId RequestId * @return Whether it was released successfully */ public boolean unlock(String lockKey, String requestId) { String script = "if ('get', KEYS[1]) == ARGV[1] then return ('del', KEYS[1]) else return 0 end"; DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); (script); (); return (redisScript, (lockKey), requestId) == RELEASE_SUCCESS; } }
3. Use examples
import ; import ; import ; import ; @RestController public class LockController { @Autowired private RedisLockUtil redisLockUtil; @GetMapping("/lock") public String lock(@RequestParam String lockKey, @RequestParam long expireTime) { String requestId = (()); if ((lockKey, requestId, expireTime, )) { try { // Execute business logic return "Locking is successful, business logic is executed"; } finally { (lockKey, requestId); } } else { return "Locking failed, please try again"; } } }
6. Things to note and optimization
1. Deadlock problem
If the client crashes while holding the lock without releasing the lock, it can result in a deadlock. To avoid this, the expiration time of the lock can be set and automatically released when the lock expires.
2. Lock competition and retry mechanism
In high concurrency environments, multiple clients may attempt to acquire the same lock at the same time, which may lead to lock competition. for
This is the end of this article about the detailed explanation of the technology of using Redis to implement distributed locks. For more related content on Redis distributed locks, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!