Note: Before reading this article, you need to have a basic understanding of Redis: Redis data structure and application. Don’t worry, little by little, first to see the basic knowledge of Redis.

What is a Redisson?

Redisson is a distributed lock based on Redis service. It is powerful and suitable for redis clusters in various modes.

Then some students will ask: what are the clustering modes of Redis? What are the characteristics of clusters?

What are the types of Redis clusters? There are four common ones, which are:

  1. Single machine mode (Single)
  2. MasterSlave mode
  3. Sentinel mode (Sentinel)
  4. Cluster mode

This is all a conceptual introduction, right? What are the characteristics of each?

But this article is not to introduce the characteristics and various advantages of the cluster model for the purpose, but can refer to the article: juejin.cn/post/684490…

Redssion loads different mode configurations of the Redis cluster

How does Redisson fit into Redis cluster? Beauty requires this spirit of inquiry, and we are all men trying to be the best programmers.

You can see how Redisson sets up the Redis cluster mode in the following code:

Its Redisson client provides the corresponding link to manage it, which loads the configuration information under the corresponding Redis cluster through the configuration mode. And create Redis link request information. ConnectionManager is an interface. What is its structure like?

This is a different link request manager implementation of Redis cluster, which ADAPTS all the links in 4 general cluster patterns (policy pattern). What is this? It takes its replication group cluster and iterates through the information of each node to determine if it has changed its role and gets the latest master node, kind of acting as its own sentinel)

How does Redisson implement distributed locking?

We first do not explore how is how to achieve, we do not say second words first to use again, good things with know.

public void run(){ RLock rLock = redissonClient.getLock("anyLock1"); // Not fair lock, default try{rlock. lock(); System.out.println(" I got the lock successfully, started to execute the concurrent operation "); }finally {// unlock operation rlock. unlock(); }}Copy the code

It works a bit like a ReentrantLock. After acquiring the lock, you need to manually release the lock.

Redisson Lock code implementation analysis

The code analysis part is boring and sleepy

But in order to be good, in order to be mature, in order to catch up with my sister, in order to be her person to rely on, boring things will become interesting.

Redisson inherited the JDK.Lock interface.

Next, let’s look at the implementation of its Lock code

We found that the call is Redisson. Lock (leaseTime, timeUnit interruptibly) method.

The default value -1 specifies the timeout period for the redis lock. TimeUnit interruptibly: Whether to respond to an interrupt \

Follow up and have a look at the tryAcquire(-1,leaeTime,unit,threadId) method. Try to get the lock operation.

When I followed up, IT turned out that there was an asynchronous fetch method inside, something that involved asynchronous programming. I was scared to wipe the sweat ~ ~ ~

Its internal to determine whether the lock specified timeout time, if the lock logic can not go, we first analyze its specified lock timeout code (leaseTime! = 1).

Enter method to discover: What scripting language is this?

This is the LUE script, which inside executes some instruction methods that call Redis.

Why write this in lUE script?

This has to do with the nature of the LUE script, which guarantees the atomicity of code instructions. Execute all at the same time and return processing logic. In fact, the code in the script is redis instruction, read is not a problem ~ ~ ~

Lock logic implementation lUE script analysis

In fact, the core of Redisson’s locking logic lies in this LUE script, which we carefully analyze.

if (redis.call('exists', KEYS[1]) == 0) then " +
        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
        "return nil; " +
        "end; " +
        "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
        "return nil; " +
        "end; " +
        "return redis.call('pttl', KEYS[1]);
Copy the code

Lue script parameter analysis

Let’s look at the parameters without looking at the code. Keys [1]:Rawname, what is Rawname? ARGV[1]: leaseTime AGRV[2]: anyLock1 ARGV[1]: leaseTime AGRV[2]: lock name How did this get generated? \

How are lock names produced?

Yes, you may wonder how this lock name is generated.

Let’s look at the code

What id does it concatenate with the local thread threadId? \

I don’t know at this point, a little confused? But look at the code

At this time found with the link configuration has a relationship, walk her, then go in. Found ConnectionManger is an interface, then I can grab a realization to found that all the bottom of the child realize inherited MasterSlaveConnectionManager

At this point, the ID starts being specified and it’s just a UUID.

ARGV[2]=UUID+”:”+threadId

Why UUID+ “:” +threadId as lock name

Why not use threadId instead of the distributed lock Id?

Because it is a distributed service, and because threadId alone does not specify which thread is executing on which server node, a globally unique prefix (UUID) is required.

Some students asked? Can we not use the UUID?

Yes, as long as the distributed lock prefixes produced by each server node are differentiated. But this requires the maintenance of each server node to write prefix, calculation is not cost-effective (I do not have the time to do this, but there is a scenario oh, you think about it), it is better to use uUID (easy to use and convenient).

Start formal analysis of the LUE script

if (redis.call('exists', KEYS[1]) == 0) then " +
        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
        "return nil; " +
        "end; " +
        "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
        "return nil; " +
        "end; " +
        "return redis.call('pttl', KEYS[1]);
Copy the code
  1. Does anyLock1 exist in Redis, if not?
  2. Filed UUID+”:”+threadId, assign the value +1 to the map data of redis whose anyLock is the key
  3. After the creation, set the timeout period to leaseTime
  4. Returns a NULL.

Isn’t this the case where there is no value and the lock thread returns for the first time? Oh, my God, you’re amazing. I figured that out.

    if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
        "return nil; " +
        "end; 
Copy the code

Let’s move on to the second code

  1. If the previous step fails, check whether the filed: UUID+”:”+threadId stored in anyLock1 is the sub-body value.
  2. If so, I do the +1 operation on the field value of anyLock1
  3. And reset the lock timeout period
  4. And returns NULL, indicating that the lock is successfully held

There is also the last lUE script, soon finished analysis, happy!!

return redis.call('pttl', KEYS[1]);
Copy the code
  1. This is to determine the thread holding the lock, and it has nothing to do with you, wait, wait to see how long you have
  2. So return PTTL, how long before you release the lock time

Beautiful isn’t that the end of analysis?

How to implement lock timeout without setting it?

So let’s go back to leaseTime=-1

Students said, this how there are two places involved ah? After the instruction is executed asynchronously, it seems to use judgment

  1. Yes, one by one, we click on it and find that it uses an internalLockLeaseTime as the timeout, the default is 30000 milliseconds \
  2. Handling the locking logic is the same as the above lue script
  3. What’s the difference?

Yes, it’s on the second part, the asynchronous execution is completed, it will judge perform scheduleExpirationRenewal method.

Which this method is in after all what ??????

Check back next week for an update on what it does inside (whisper: WatchDog).

conclusion

Redisson realize distributed lock, its internal not only these, through observation and application, found its powerful function, it has realized JDK fair lock in unfair lock, read and write lock, red lock, biased lock and so on. Function of the powerful, is not aroused your desire to learn.

I also yearn for blue, wish to be your blue, you know? It will work out one day. Thank you