This article will talk about locks in Redis, and introduce why locks are used. Do we really need Redlock (redis distributed lock)? I hope it will be helpful to everyone!
Why use locks
In a k12 education company I worked for, we had a The business scenario is like this. The business side has to arrange classes for students. Occasionally, there will be feedback that the student's class hours are clearly sufficient but there are insufficient class hours. When the page is refreshed, it is found that the student's class hours are no longer enough. What’s even more frightening is that occasionally students’ class hours will be deducted into negative numbers (the company’s class hours will be used for free). [Related recommendations: Redis video tutorial]
Another example is the following example
The above two questions are sent to problems arising from our business. The core solution to this problem is that only one request can be allowed to read and write these sensitive (important) data at the same time. Therefore, distributed locks must be used at this time to limit the concurrent execution of the program.
What are the problems with setnx
Let’s first take a look at how to implement distributed locks using Redis, which everyone must be familiar with. For example, for the student class scheduling problem mentioned at the beginning of my article, we can lock it like this
This is how we routinely use setnx to implement locking.
Now we assume there is such a scenario. When requesting A to obtain the lock, the program hung up in step 2 when scheduling classes for students, and the lock was not released. Then the lock becomes a deadlock. The next request to operate the same student will never get the lock, and the student cannot be scheduled. At this time, you need to manually release the lock.
In order to solve the deadlock problem, we add an expiration time to the lock.
After adding the expiration time, if request A does not actively release the lock, it will be actively released after the lock expires, so that request B can also obtain the lock processing business logic. But if the expiration time is added, the program crashes between steps 1 and 2. Then there will still be a deadlock problem. The root of this problem is that the two instructions setnx and expire are not atomic instructions. So it would be nice if setnx and expire could either execute all or none of them.
For this reason, a large number of extension packages emerged in the community before Redis2.8 to solve this problem. In order to control this chaos, the official added the extended parameters of the set instruction in version 2.8 so that the setnx and expire instructions can be executed together, so now we should use distributed locks like this
This looks perfect, and has achieved our expectation "It would be great if setnx and expire could either execute all or none of them". Let's assume that we now have the following scenario:
A request has now obtained the lock, and the lock timeout is set to 5 seconds. In step 2, the business logic is executed, but for some reason the business logic has not been completed after 5 seconds. At this time, the lock is automatically released due to timeout. At this time, request B also came, and after getting the lock, the business logic started to be executed. At this time, the business logic of A's request has been executed, and the third step is started, and the lock is released. At this time, the lock was obtained by B's request, but was released by A's request. Then C request can get the lock. At this time, request B and request C will cause concurrency problems. So it can be seen from this example that the setting of the expiration time in distributed locks is very important. If the set time is less than the response time of this interface, concurrency problems will still occur. Therefore, we can refer to the monitoring of interface response time to set the lock expiration time.
Redlock
Our above solutions are all based on single-point Redis implementation. The single-point Redis implementation of distributed locks can basically meet 95% of business scenarios. The remaining 5% are business scenarios with extremely strict requirements on data consistency and zero tolerance for lock loss. At this time, you have to consider Redlock. As for single-point Redis, even if it ensures high availability through sentinel, if the master node switches master-slave for some reasons, and if the master-slave data synchronization is not timely, data loss will occur, and lock loss will occur.
Assume that there are multiple Redis instances. These nodes are completely independent and do not need to use replication or any system for coordinating data. We assume that there are 5 Redis master nodes. In order to obtain the lock, the steps for the client will be It becomes like this:
Get the current server time in milliseconds
Try to use the same key and random value to acquire the lock. The client should have a timeout period when acquiring the lock on each machine. For example, if the lock expiration time is 10s, then acquire a single node lock. The timeout time should be about 5 to 50 milliseconds. The purpose of this is to ensure that the client does not spend extra time connecting to the failed machine! If the data is not obtained within the timeout period, the node will be abandoned and the next Redis node will be obtained.
After the acquisition is completed, obtain the current time minus the time obtained in step 1, if and only if the client obtains the lock from more than half (here, 3 nodes) of the Redis nodes and If the time to acquire the lock is less than the lock timeout, it proves that the lock is effective!
If the lock is acquired, the real valid time of the key is equal to the valid time minus the time used to acquire the lock (the result calculated in step 3).
If more than half of the machines that acquire the lock are not satisfied, or the lock timeout is negative after calculation, or other abnormal operations, the system will try to unlock all instances, even if some Redis instances are not locked at all. If the lock is not successful, it prevents some nodes from acquiring the lock but the client does not get a response and the lock cannot be reacquired for a period of time
So we can see that redlock actually It is a lock that seems more reliable than single-point Redis.
If you are a Node.js programmer like me, then there is a third-party library redlock that you can use directly.
Do we really need redlock?
There is actually another voice about redlock, Martin Kleppmann (researcher at Cambridge University, engaged in database, The TRVE DATA project in the intersection of distributed systems and information security wrote an article blog and expressed some views on redlock. If you are interested, you can read it. Redis author Salvatore also made some responses to the questions in this article, which is quite interesting. The main points of the author's blog are as follows:
There are no more than two uses of distributed locks:
If it is for efficiency, there is no need to bear the cost and complexity of Redlock. Compared with the cost of sending several more emails due to lock loss and the cost of running 5 Redis servers, it is better to only use a single Redis Example. If you are using a single Redis instance and the Redis node suddenly loses power or crashes, or other problems occur, of course the lock will be lost at this time. But if you're just using the lock as an efficiency optimization, and this crash doesn't happen often, it's not a big deal. This "no big deal" scenario is exactly where Redis excels. At least if you rely on a single Redis instance, everyone looking at the system will be able to locate the problem more easily.
If it is for correctness, then strictly speaking, redlock does not have the strictness of strong consistency at all. Some examples are given
Timing and system clocks make dangerous assumptions and rely heavily on the clock of each server. Because there is a GC in the system, the entire server is rammed during GC, and time is stagnant, so we cannot have a strong dependence on the clock.
No token. The server does not issue a token every time the client acquires the lock. The server should verify that the client's token must be consistent with the current token of the server during each operation to make it difficult to operate the lock.
The author mainly focuses on the above points of view. If you are interested, it is recommended to read the original article.
For more programming-related knowledge, please visit: Introduction to Programming! !
The above is the detailed content of A brief analysis of locks in Redis, let's talk about Redlock (redis distributed lock). For more information, please follow other related articles on the PHP Chinese website!