Topic 4 Redis distributed lock - redismission

Topic 4 Redis distributed lock - redismission

1, Introduction to Redis distributed lock

Official interpretation

There are two main points after interpretation:

1. A typical example of distributed locking is that different processes must share resources exclusively

2. There are various implementations of distributed locks, but we commonly use Redis distributed lock

2, What is Redisson?

Firstly, redistribute provides the simplest and most convenient method to use Redis.

Redisson aims to promote users' Separation of Concern for Redis, so that developers can focus more on business.

Redisson is a Java in memory data grid implemented on the basis of Redis.

IMDG, using memory as the primary storage medium.

IMDG features can be summarized as follows:

  • Data is distributed and stored on multiple server s.

  • Each server is in active mode.

  • Data models are generally object-oriented and non relational.

  • Servers are often added or removed as needed.

Technical features of Redisson

  • Netty framework: Redisson adopts the netty framework based on NIO, which can not only serve as the underlying driver client of Redis, but also provide the connection function for Redis in various configuration forms, send Redis commands in synchronous, asynchronous, asynchronous stream or pipeline forms, execute and process LUA scripts, and process the returned results

  • Basic data structure: encapsulate the native Redis Hash, List, Set, String, Geo, HyperLogLog and other data structures into the most familiar structures in Java, such as Map, List, Set, general Object Bucket, Geospatial Bucket, and HyperLogLog,

  • Distributed data structure: on this basis, it also provides distributed Multimap, LocalCachedMap, SortedSet, ScoredSortedSet, LexSortedSet, Queue, Blocking Queue, Bounded Blocking Queue, Deque, Blocking Deque, Blocking Fair Queue, Delayed Queue, Bloom Filter, AtomicLong, AtomicDouble, BitSet and other distributed data structures that Redis does not originally have.

  • Distributed Lock: Redisson also implements higher-level application scenarios such as distributed Lock mentioned in Redis documents. In fact, Redisson does not stop there. On the basis of distributed locks, it also provides MultiLock, ReadWriteLock, Fair Lock, RedLock, Semaphore, PermitExpirableSemaphore and CountDownLatch, which are the basic components that are important for multi-threaded high concurrency applications. It is through the implementation of Redis based high-level application solutions that Redisson has become an important tool for building distributed systems.

  • Node: as an independent node, Redisson can be used to independently execute remote tasks published by other nodes to the distributed execution service and distributed scheduling service.

3, Integrate Redisson

There are two schemes for integrating Redisson with Spring Boot:

  • Programmatic configuration.
  • File mode configuration.

This chapter introduces how to integrate Redisson in a programmatic way.

3.1 import dependency

<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.15.5</version>
</dependency>

3.2 user defined configuration class

@Configuration
public class MyRedissonConfig {
    /**
     * Redisson is used through the RedissonClient object
     * @return
     * @throws IOException
     */
    @Bean(destroyMethod="shutdown") // Call the shutdown method after the service is stopped.
    public RedissonClient redisson() throws IOException {
        // 1. create configuration
        Config config = new Config();
        // Cluster mode
        // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
        // 2. create a RedissonClient example according to Config.
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

3.3 test configuration class

Create a new unit test method

@Autowired
RedissonClient redissonClient;

@Test
public void TestRedisson() {
    System.out.println(redissonClient);
}

output

org.redisson.Redisson@77f66138

4, Distributed reentrant lock

4.1 reentrant lock test

Redisson distributed reentrant lock RLockJava object based on Redis implements java Util Concurrent Locks Lock interface. It also provides asynchronous, Reactive, and RxJava2 standard interfaces.

RLock lock = redisson.getLock("anyLock");
// Most common usage
lock.lock();

Two points for testing reentrant locks:

1. Multiple threads preempt locks. Do you need to wait for the following locks?

2. If the service of the thread that preempted the lock stops, will the lock be released?

4.1.1 question 1: is the reentrant lock blocked?

demo program, code flow, set the lock, then the yoke, print the thread ID, and release the lock after waiting for 10s.

@ResponseBody
@GetMapping("test-lock")
public String TestLock() {
    // 1. acquire a lock. As long as the name of the lock is the same, the acquired lock is the same lock.
    RLock lock = redisson.getLock("WuKong-lock");

    // 2. locking
    lock.lock();
    try {
        System.out.println("Lock successfully. Execute the following code. thread  ID: " + Thread.currentThread().getId());
        Thread.sleep(10000);
    } catch (Exception e) {
        //TODO
    } finally {
        lock.unlock();
        // 3. unlocking
        System.out.println("Finally´╝îThe lock was released successfully. thread  ID: " + Thread.currentThread().getId());
    }

    return "test lock ok";
}

First, verify the first point and test the preemptive lock with two http requests.

Requested URL: http://localhost:11000/question/v1/redisson/test/test-lock

The thread ID corresponding to the first thread is 86. After 10 seconds, release the lock. During this time, the second thread needs to wait for the lock to be released.

After the first thread releases the lock, the second thread obtains the lock and releases the lock 10 seconds later.

4.2 will the lock be released after the service is stopped?

If the service suddenly stops while thread A is waiting, will the lock be released? If it is not released, it will become A deadlock, blocking other threads from acquiring the lock.

Let's take A look at the result of Redis client query after thread A obtains the lock, as shown in the following figure:

The Wukong lock has a value, and you can see that the TTL is getting smaller, indicating that the Wukong lock has its own expiration time.

Through observation, after 30 seconds, Wukong lock expired and disappeared. This indicates that the lock occupied will be released automatically after the Redisson is shut down.

What is the principle? Here is a concept, watchdog. In Redis, you can customize the expiration time of the key, which is generally 30s by default

5, Distributed read / write lock

Redisson distributed reentrant read / write lock RReadWriteLock Java object based on Redis implements java Util Concurrent Locks Readwritelock interface. Read lock and write lock inherit RLock interface.

A write lock is an exclusive lock (mutex lock), and a read lock is a shared lock.

  • Read lock + read lock: it is equivalent to no lock and simultaneous reading.
  • Read lock + write lock: the write lock needs to wait for the read lock to release the lock.
  • Write lock + write lock: mutually exclusive. You need to wait for the other party's lock to be released.
  • Write lock + read lock: the read lock needs to wait for the write lock to be released.

The example code is as follows:

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// Most common usage
rwlock.readLock().lock();
// or
rwlock.writeLock().lock();

In addition, Redisson also provides the parameter of leaseTime to specify the locking time through the locking method. After this time, the lock will be unlocked automatically.

// Automatic unlocking after 10 seconds
// No need to call the unlock method to unlock manually
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// or
rwlock.writeLock().lock(10, TimeUnit.SECONDS);

// Try to lock, wait for 100 seconds at most, and unlock automatically 10 seconds after locking
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// or
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

6, Distributed signal lock

The distributed semaphore Java object RSemaphore of Redisson based on Redis adopts the java Util Concurrent Semaphore similar interface and usage. It also provides asynchronous, Reactive, and RxJava2 standard interfaces.

As for the use of semaphores, you can imagine this scenario. There are three parking spaces. When the three parking spaces are full, other cars will not stop. The parking space can be compared to a signal. Now there are three signals. One signal is used when the car stops once, and one signal is released when the car leaves.

We use Redisson to demonstrate the above parking spaces.

First define a method to occupy a parking space:

/**
* Parking space
* 3 parking spaces in total
*/
@ResponseBody
@RequestMapping("park")
public String park() throws InterruptedException {
  // Acquire semaphore (parking lot)
  RSemaphore park = redisson.getSemaphore("park");
  // Get a signal (parking space)
  park.acquire();

  return "OK";
}

Define another method to leave the parking space:

/**
 * Release parking space
 * 3 parking spaces in total
 */
@ResponseBody
@RequestMapping("leave")
public String leave() throws InterruptedException {
    // Acquire semaphore (parking lot)
    RSemaphore park = redisson.getSemaphore("park");
    // Release a signal (parking space)
    park.release();

    return "OK";
}

For simplicity, I use the Redis client to add a key: "Park". The value is equal to 3, which means that the semaphore is park. There are three values in total.

Then use postman to send a park request to occupy a parking space.

Then check the value of park on the redis client and find that it has been changed to 2. Continue to call twice and find that the park is equal to 0. When you call the fourth time, you will find that the request has been waiting, indicating that there are not enough parking spaces. If you want to avoid blocking, you can use tryAcquire or tryAcquireAsync.

We call the method of leaving the parking space, and the value of park becomes 1, which means that there is 1 parking space left.

Note: if you release the semaphore for many times, the remaining semaphore will increase all the time, instead of being capped after 3.

Other distributed locks:

  • Fair Lock
  • Interlock (MultiLock)
  • RedLock
  • ReadWriteLock
  • PermitExpirableSemaphore
  • Lockout (CountDownLatch)

Tags: Java Redis Distribution

Posted by crazyeight on Mon, 30 May 2022 03:56:32 +0530