Distributed locks are often used in multi-instance deployments and distributed systems. This is because JVM-based locks cannot meet the needs of multi-instance locks. This article will talk about how redis implements distributed locks through Lua scripts, which is different from Redission on the Internet is completely implemented manually
Let's first look at what a lock-free situation can cause:
This is a common function to update the user's age. The code of each layer is as follows, accessing the controller layer, one update, one query
This is the service layer. We use the contdownlatch starter gun to simulate the simultaneous concurrency of threads. The starter gun is set to 32, that is, 32 threads request to modify the age at the same time.
Here we use the thread pool to submit multi-threaded tasks. Look at the code to know that we already have the operation to judge the age. When the query user query is greater than 0, we will adjust the method of updating the user's age -1. Wait and see if it works.
Here is the sql, you can see two sqls, one to query the user's age, and the other to reduce the user's age by 1 each time.
Here is the user data, we can see that the user whose UID is UR12324, his age is 30, then we will adjust 32 threads to reduce his age
we request this method
Then look at the result:
It can be seen that the age in the library has been reduced to -2. In the case of no lock, the query comparison has no effect. At this time, if a synchronized or lock lock is added, this situation can definitely be avoided, but we discuss in this article. In a multi-instance or distributed environment, this locking method will still cause problems. If you are interested, you can try it out.
Let's start to implement a redis distributed lock to avoid this situation. Let's talk about the implementation idea first:
1. Before the thread requests access, call the lock method, and after the lock, a random number is generated and stored in the thread local variable and a key of redis. The key is set to be valid for 200ms, and the specific value is adjusted according to the business execution time. , the lock is successful;
2. Other threads try to access their local variables and compare them with a key in redis. If they are inconsistent, it means there is a lock. This thread sleeps for a period of time, and then tries to lock it again;
3. The thread that successfully locks deletes the lock it holds after the operation is completed (implemented with lua, to ensure atomicity, in the process of comparing and deleting locks, other threads will not successfully lock), and let other threads again lock to perform tasks;
Note: The lock time is 200ms to prevent deadlock after the thread hangs up, and it will be automatically released after 200ms
Let's take a look at the lock code we wrote:
Fragment 1: Use redislock to implement lock to override its method
Fragment 2: Try the locking method
Fragment 3: Unlock method, here first get its random number from the thread local variable, then call the lua script, compare it with the key in redis, if it is the same, delete it, otherwise return 0;
This is a lua script method. This method can ensure the atomicity of judgment and deletion. During this process, no thread can operate this key.
So far, we have basically finished writing the lock to test whether it is useful:
We add locking and unlocking methods before and after this method. The way of using it is the same as the lock lock. Let's restore the age to 30 and test it later.
Look at the log first
Here you can see the situation where each thread competes for locks, and then look at the execution results
Here we can see that although 32 threads execute concurrently, this value will not become negative, and the lock is successful.
We can see that the last 2 threads did not execute the method
At this point, it means that the locking is successful. You can test it in a distributed environment. It is more obvious what to do after the unlocking fails in extreme cases. It is more flexible than redission. Redis with lock is preferably a single instance. There may be problems in the cluster, and if there is a chance, we will use zk to implement it.
Source: https://www.toutiao.com/a6552304385152516621/?tt_from=mobile_qq&utm_campaign=client_share×tamp=1525647342&app=news_article_lite&utm_source=mobile_qq&iid=31152232259&utm_medium=toutiao_android