Realization and problems of distributed lock

In the case of multi-threaded, we can use locks to ensure that a block of code can only be accessed by one thread at a time. For example, Java's synchronized keyword and Reentrantlock class and so on.

This way you can ensure that multiple threads within the same JVM process synchronously.

 

If a distributed clustered environment, how to ensure that different nodes thread synchronization enforce it?

 

In a distributed system, how to achieve different threads to synchronize access to the code and resources?

For single-process concurrency scenarios, we can use the lock language and class libraries provide. For distributed scenario, we can use the distributed lock.

So how can we achieve a distributed system lock it?

Distributed Lock There are many methods to achieve, look at the following simple list.

Implementation of distributed lock What?

1.Memcached Distributed Lock

Use of Memcached add command. This command is an atomic operation, only if the key does not exist, in order to add successful, it means that the thread has been locked.

2.Redis Distributed Lock

And Memcached manner similar to the setnx use Redis commands. This command also is an atomic operation, only if the key does not exist, in order to set successful. (Setnx command is not perfect, follow-up will introduce alternatives)

3.Zookeeper Distributed Lock

Zookeeper node using the temporary order to achieve lock and distributed queue. Zookeeper originally designed, is to achieve a distributed lock service.

First talk about the distributed lock Redis, this implementation more representative.

How to implement a distributed lock with Redis?

The basic flow of distributed lock Redis is not difficult to understand, but to write perfect, it is not so easy. Here, we need to understand three core elements distributed lock implementation:

1. Locking

The easiest way is to use the setnx command. lock key is a unique identifier, determined by business name. For example you want to lock a commodity spike activity, you can give key named "lock_sale_ commodity ID". And what value is set to it? The lock value is a randomly generated UUID. We can tentatively set to 1. Locking the following pseudocode:    

setnx (key, 1)
When a thread executes setnx returns 1, indicating that the original key does not exist, the thread has been successfully locked; when a thread executes setnx returns 0, indicating that key already exists, grab the thread lock failure.

2. Unlock

There must have unlocked lock. When threads get locked task is finished executing, you need to release the lock, so that other threads can enter. The easiest way is to release the lock del instruction execution, the pseudo-code is as follows:

del (key)
after releasing the lock, other threads can continue setnx command to obtain the lock.

3. Lock timeout

Lock timeout What does it mean? If a thread get locked during the execution of the task hang up, too late to explicitly release the lock, this resource will be locked forever, and never to come in another thread.

So, setnx the key must set a time-out time, in second, to ensure that even if not explicitly released, the lock should be released automatically after a certain time, to avoid deadlock. setnx timeout parameter is not supported, so the need for additional instructions, pseudo-code as follows:

expire (key, 30)
together, we distributed the first edition of the pseudo-code lock to achieve the following:

IF (SETNX (Key,. 1) ==. 1) {
    The expire (Key, 30)
    the try {
        do something ......
    } {the finally
        del (Key)
    }
}
The above pseudo-code implementation of distributed simply locks, consider the practical application scenarios will find that to achieve the above distributed locks there are three fatal problems:

1. setnx and non-atomic the expire

Imagine an extreme scenario, when a thread execution setnx, success has been locked:

 

setnx just executed successfully, not enough time to execute expire instruction node 1 Duang bang hung up. 

 

As a result, the lock did not set an expiration time, become "immortal", another thread could not get locked.

How to solve it? setnx instruction itself does not support incoming timeout, fortunately Redis 2.6.12 above instruction set to increase the optional parameters, the following pseudo-code:

set (key, 1,30, NX)
so that you can replace setnx instructions.

2. del cause accidental deletion

Is an extreme scenario, if a thread has been successfully locked, and set the timeout time is 30 seconds.

 

If for some reason the thread A executed very slowly, after 30 seconds have not been performed, it is automatically released when the lock expired, the thread B has been locked.

 

Subsequently, the thread A task execution is over, then thread A executed del instructions to release the lock. But this time not executing the thread B, thread A thread is actually deleted B plus locks. 

 

How to avoid this situation? You can make a judgment before del release the lock, verify the current lock is not added their own locks.

As for the specific implementation, you can put the current thread ID as the value at the time of locking, and verify key before deleting the corresponding value is not its own thread ID.

Lock:

String threadId = Thread.currentThread().getId()
set(key,threadId ,30,NX)
解锁:

IF (the threadId .equals (redisClient.get (Key))) {
    del (Key)
}
can also release the lock, the default value is determined by the value of the UUID of the lock is not locked, a lock if the lock is performed delete freed.

However, this also implies a new question, judgment and release the lock are two independent operations, not atomic.

To achieve certification and atomic deletion process, you can use Lua scripts to achieve. This would ensure the correctness and verification of the removal process.

3. When the possibility of concurrent

Or scene just described the second point, although we avoid the situation thread A mistake delete key, but at the same time there are A, B two threads access code block, is still not perfect.

How to do it? We can make a thread to acquire a lock to open a daemon thread, used to lock about to expire "life."

 

When the 29 seconds have passed, the thread A has not been performed, this time daemon thread will execute expire instructions for the lock "continued life" for 20 seconds. Daemon thread begins execution from 29 seconds to execute once every 20 seconds.

 

A thread when executing the task, explicitly switch off guard thread.

 

Another case, if the node 1 of a sudden power outage, as the guardian of thread A and thread in the same process, a daemon thread will stop. This lock to a timeout when no one gave it continued life, it is automatically released.

 

Redis content on distributed lock on to introduce it here. 
----------------
Disclaimer: This article is the original article CSDN bloggers "kongmin_123", and follow CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement. .
Original link: https: //blog.csdn.net/kongmin_123/article/details/82080962

Guess you like

Origin www.cnblogs.com/lice-blog/p/11616429.html