Analysis of Redis Distributed Lock Principle
Keywords:
Redis
Java
github
- Redis Distributed Lock Command
Setnx if and only if the key does not exist. If the given key already exists, setnx does nothing. Setnx is the abbreviation of "set if not exists" (if not, set). Setnx has atomicity.
get set first gets the old value, then sets the new value, and returns the old value of the key, which is atomic. When the key exists but is not a string type, an error is returned; when the key does not exist, it returns nil, which is null in Java.
expire sets the validity of key
del deletes key
- Combination with timestamp
The value of a distributed lock is composed of the current system time System.currentTimeMillis()+Key validity period.
- Redis Distributed Lock Flow Chart
- Redis Distributed Lock Optimized Edition Process
This optimized version of the process here shows that if the lock is successfully acquired, then the business logic is executed according to the process, the lock is executed, and the lock is deleted. If the lock is not acquired, continue to determine the timestamp to see if the lock can be reset and acquired. First get the current value, and compare the current system time and the value obtained. If the current time is greater than the value, the lock has expired, then perform the getset operation to reset the value of the key. If the old value returned does not exist, say If the key has been deleted, or the old value exists, and the value is the same as that of the previous get, it means that the lock is actually acquired at this time, and then the corresponding business logic is executed.
@Scheduled(cron = "0 */1 * * * ?")
public void closeOrderTask() {
log.info("Close Order Timing Task Start");
long lockTimeOut = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeOut));
if (setnxResult != null && setnxResult.intValue() == 1) {
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
} else {
String lockValueA = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
if (lockValueA != null && System.currentTimeMillis() > Long.parseLong(lockValueA)) {
String lockValueB = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeOut));
if (lockValueB == null || (lockValueB != null && StringUtils.equals(lockValueA, lockValueB))) {
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
} else {
log.info("No distributed lock was acquired:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
} else {
log.info("No distributed lock was acquired:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
}
log.info("Close Order Timing Task End");
}
private void closeOrder(String lockName) {
RedisShardedPoolUtil.expire(lockName, 5);
log.info("Obtain{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.out", "2"));
iOrderService.closeOrder(hour);
RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
log.info("release{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
log.info("********************************************");
}
Click on GitHub to view the code
Posted by errtu on Fri, 10 May 2019 23:30:02 -0700