Self growth of serial number by distributed lock

Keywords: Programming Redis Zookeeper

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:

  1. Servcie to seize the lock
  2. Set the lock expiration time to 2S (to prevent deadlock) after successful preemption, and return to the status of successful preemption
  3. Servcie performs business operations
  4. 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;
    }

Posted by techjosh on Wed, 15 Apr 2020 08:27:53 -0700