Redis Distributed locks have been introduced in previous articles . Now there is an easy to understand way to say it again .

Before entering the text , Let's think with questions first :

When do I need distributed locks ?
plus , Do you pay attention to the location of the unlocked code ?
How to avoid deadlock
How much is the timeout appropriate ?
How to prevent locks from being released by other threads
How to implement reentry lock ?

<> When to use distributed locks ?

Here I borrow a description from brother code
The moment of sperm ejection , Billion flow rushed to the egg , Only one sperm is lucky enough to bind to an egg .

The creator wanted to ensure that there was only one 「 sperm 」 Can obtain 「 egg 」 Your favor , When a sperm enters , The shell of the egg changes , Close the channel and block the rest of the sperm out .

A billion level of sperm is like 「 Concurrent 」 flow ;
Eggs are like shared resources ;
The special protein in the egg shell that allows only one sperm to enter is a lock .

Multi node cluster , There will be more JVM process , We need an intermediary to achieve the same effect , Only one is allowed JVM A thread in is eligible to operate on shared resources .
Distributed locks are used to control the same time , only one JVM A thread in a process 「 sperm 」 Can access protected resources 「 egg 」.

「 Every life , They are the best of the 100 million players 」, come on .

<> Getting started with distributed locks

What characteristics should distributed locks meet ?

mutex : At any given moment , Only one client can hold the lock ;
No deadlock : It is possible to obtain a lock at any time , Even if the client acquiring the lock crashes ;
fault-tolerant : As long as most Redis All nodes have been started , The client can acquire and release the lock .

The previous article mentioned that we can use SETNX To lock .
Describe a scene for everyone :
Everyone is tired of typing code all day , I want to go for a massage to relax . among 28 Technician No. 1 is young and beautiful, and the service is good , Everyone likes it , Therefore, there is a large amount of concurrency , Distributed lock control is required .
Only one customer can make an appointment at a time 28 Technician No .
Zhang San's appointment 28 Technician No

Here you can see that Zhang San made an appointment with the technician successfully , Li Si will make an appointment again .

Li Si can't make an appointment , Because this time 28 Technician No. 1 wants to serve Zhang San, the customer .
this moment , Zhang San who has successfully applied can enjoy it 28 number Technician services ( shared resource ).
After enjoying , Release the lock in time , For the latecomers to enjoy 28 number Technician Service Opportunities .
So here comes the problem , How do I release the lock ?
It's simple . Just delete it .

It's not that simple .
This scheme has a problem that the lock cannot be released , The scenarios causing this problem are as follows :

Suddenly received an online alarm during massage , He picked up his pants and ran to the company , Not implemented in time DEL Release lock ( Client processing business exception , The lock cannot be released correctly );
Central muscle infarction and hiccup during massage , Cannot execute DEL instructions .

such , This lock will remain occupied , Locked in my hand , I hung up , In this way, other clients will never get the lock again .

This metaphor may not be very good , Put it another way , Take the shared power bank as an example , When you rent a shared power bank , It's equivalent to charging this power bank ( Shared services ) be locked , If you return it, you release the lock . If you forget, return it , Then other customers will never be able to rent your power bank . Is it much easier for everyone to understand .

To put it bluntly, this scheme is an exception that causes the lock not to be released .
At this time, we can think of , Set a timeout for the lock . Doesn't that solve the problem .
Redis 2.6.X after , Official Expansion SET Parameters of the command , At the same time, set the semantics of timeout , And satisfy atomicity .
SET key value NX PX 30000
PX 30000: Indicates that the lock has a 30 Seconds auto expiration time .

TTL This is the timeout , When more than 30 The lock will be deleted automatically after seconds .
Can you safely enjoy the one-stop service ?
No, There is also a scenario that will lead to the release of someone else's lock :

customer 1 Lock acquired and set successfully 30 seconds until timeout ;
customer 1 Execution is slow for some reasons ( Network problems , happen FullGC……), Yes 30 Seconds is still not finished , But the lock has expired 「 Automatically released 」;
customer 2 Successfully applied for locking ;
customer 1 Execution complete , implement DEL Release lock command , At this time customer 2 The lock was released .

There are two key issues that need to be addressed :

How to reasonably set the expiration time ?
How to avoid deleting locks held by others .

<> Set lock timeout correctly

You can't write nonsense at this time , Generally, multiple tests shall be conducted in the test environment according to the requirements , Then, after the pressure measurement of multiple wheels , For example, calculate the average execution time 200 ms.

Then the lock timeout is enlarged to the average execution time 3~5 times
Because if there is a network in the operation logic of the lock IO operation ,JVM FullGC etc. , The online network will not always be smooth sailing , We should leave buffer time for network jitter .

Then I'll set it bigger , Such as setting 1 Hours are not safer ?

Don't drill ox horn , How big is big ?

Setting time too long , Restart in case of downtime , That means 1 Within hours , All nodes of distributed lock service are unavailable .

Do you want the O & M to delete this lock manually ?

As long as I really won't hit you .

Of course, this scheme is not perfect , Because the time size is not appropriate no matter how it is set .

We can let the thread that obtains the lock open a daemon thread , Used to give locks that are about to expire 「 Endurance 」.

Set an expiration time when locking , At the same time, the client opens a 「 Daemon thread 」, Regularly detect the expiration time of this lock .

If it's about to expire , But the business logic has not been executed yet , Automatically renew this lock , Reset expiration time .

You may not be able to write it yourself , however Redisson Helped you solve the problem , And when the program releases the lock ,

redission There is also a broadcast mechanism to notify other waiting threads that they can obtain locks , about Redisson I won't say more , upper

An article talked about this problem .