Distributed lock (based on Redis implementation)

Operation note: After entering redisson on github, select the following picture to enter the Redisson project introduction (Chinese document)Insert picture description here

One, the concept of distributed locks

The purpose of distributed locks is: in a distributed environment, for a certain operation (insert a piece of data from the database) to be executed only once, to avoid a series of problems caused by repeated data operations, the setnx command and lua in Redis are used Script to implement distributed locks to solve the above problems.

Two, several situations of using the setnx command

2.1. What should I do if there is an exception in the business code and the command to execute the release lock (delete lock) cannot be executed, resulting in a deadlock (the lock is not released)?

The solution is: try{}finally{} can be used to solve the problem, but if the business code is executed and the machine suddenly loses power, what should I do?
The final solution is: set the expiration time of the lock, even if the lock is not deleted, the expired lock will be deleted automatically
Insert picture description here

2.2. Flashing (downtime) between setting the lock and setting the expiration time will still become a deadlock. How to solve it?

The solution is: use Redis' setnx ex command, which is a combination of setting lock + setting expiration time, and it is also an atomic operation.

Insert picture description here

2.3. When deleting the lock, due to the timeout of the business code, the lock expires early and the lock of someone else is deleted, what should I do?
2.4. If the business times out, other threads will also get the lock and enter the business operation, resulting in repeated business operations

Solve the above problem: when occupying the lock, set the value to uuid, when deleting, compare

Insert picture description here

2.5. Since the value of uuid is compared (to get the value from Redis), and the value is deleted, it is not an atomic operation. When obtaining the uuid value, it may be time-consuming, resulting in the final deletion of the lock of another thread. What should I do?

Solution: compare uuid value + delete value after successful comparison = atomic operation, you can know from the official Redis document, you can use lua script

Insert picture description here
Insert picture description here

2.6. The final form is as follows: When locking and unlocking, ensure atomicity

Insert picture description here
Final code:

 @Test
    public void testRedisHadoop(){
    
    
        String uuid = UUID.randomUUID().toString();
//        占锁(设置值),并且设置过期时间。这是一个Redis的原子命令
//        NX和EX
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);

        if(lock){
    
    
//            加锁成功,执行业务
            try{
    
    
                System.out.println("业务执行。。。。");
            }finally {
    
    
                //            获取值对比+对比成功处理=原子操作------lua脚本
//            通过uuid来删除锁,以防删除别人的锁或者
//            String lockValue = (String) redisTemplate.opsForValue().get("lock");
//            if(uuid.equals(lockValue)){
    
    
//                redisTemplate.delete("lock");
//            }

                //lua脚本
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                        "then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";

                //删除锁
                Object lock1 = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid);

            }




        }else {
    
    
            System.out.println("获取锁失败,继续尝试");
            testRedisHadoop();//自旋锁
        }


    }

Three, Redisson's distributed lock -------- reentrant lock

If method b is called in method a, a adds a lock marked as 1, and b also adds a lock marked as 1.
If it is a ** reentrant lock, then when the a method is executed, the b method inside does not need to wait for a to release the lock, and directly uses the lock of the a method.
If it is a
non-reentrant lock, ** then when the a method is executed, the b method inside needs to wait for a to release 1 lock before taking 1 lock and then executing.

3.1. Two locking and reloading methods for reentrant locks (see the figure below)

Insert picture description here

Four, redis read-write lock

The role is: get the latest data

Write lock is an exclusive lock (mutual exclusion lock, exclusive lock), read lock is a shared lock.

When the write lock is in operation, the read lock can only wait. If there is no write lock in operation, the read lock is shared, the same as no lock.

Insert picture description here

4.2. Supplementary description of read-write lock

Read + write: There is a read lock, and write needs to wait. ======= When the read lock is in progress, the write lock needs to wait for the read lock to be released (execution is complete) before it can be executed.
Read + Read: Equivalent to unlocked state. All current read locks will be successfully locked at the same time.
Write + Read: Read lock and wait for write lock to release.
Write + Write: Blocking mode (must get until).
Summary: As long as there is a write lock, you must wait.

Five, the blocking of redis

Insert picture description here

Six, redis semaphore (Semaphore)

6.1. Basic principles of use:

Insert picture description here

6.2. It can be used for current limiting, the specific principle is as follows:

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_43983411/article/details/110679363