1. introduction
In a distributed system, a service can start multiple replicas. When multiple replicas do one thing at the same time, there will be a problem of parallel. If there is a problem of data serial number duplication when new data is added, there are many ways to solve this problem, such as distributed locks, message queues, etc., in which distributed locks are divided into redis according to middleware S distributed lock, zookeeper distributed lock, db distributed lock and other versions. Today, I will introduce my redis distributed lock.
General process:
- Servcie to seize the lock
- Set the lock expiration time to 2S (to prevent deadlock) after successful preemption, and return to the status of successful preemption
- Servcie performs business operations
- Notify Redis to release the lock after the Service business operation is completed
2. implementation
1. Package distributed lock
@Component public class RedisLock implements Lock { private static String lockKey = "YC_RedisLockKey"; private static int LockExpire = 1000; private ThreadLocal<String> localValue = new ThreadLocal<>(); @Autowired private RedisTemplate redisTemplate; public void setKey(String category) { lockKey = "YC_RedisLockKey_" + category; } @Override public void lock() { if (tryLock()) { return; } try { Thread.sleep(10); } catch (Exception ex) { ex.printStackTrace(); } lock(); } @Override public boolean tryLock() { String uuid = UUID.randomUUID().toString(); if (redisTemplate.opsForValue().setIfAbsent(lockKey,uuid,LockExpire,TimeUnit.MILLISECONDS)) { // redisTemplate.expire(lockKey, LockExpire, TimeUnit.SECONDS); localValue.set(uuid); return true; } return false; } @Override public void unlock() { if (localValue.equals(redisTemplate.opsForValue().get(lockKey))) { redisTemplate.delete(lockKey); } } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public Condition newCondition() { return null; } }
2. Call distributed lock
/** * Get next serial number * * @param category Serial number classification * @return Ex.:PT00000012 * @throws Exception */ public String getNext(String category) throws Exception { return category + String.format("%08d", getAndIncrement(category)); } private Long getAndIncrement(String category) throws Exception { String dataKey = "YC_RedisDataKey_" + category; Long num; redisLock.setKey(category); redisLock.lock(); Object obj = redisTemplate.opsForValue().get(dataKey); if (obj == null) { redisTemplate.opsForValue().set(dataKey, 1L); num = 1L; } else { num = Long.valueOf(obj.toString()); redisTemplate.opsForValue().set(dataKey, ++num); } redisLock.unlock(); return num; }