Home >Database >Redis >Why is distributed lock needed in Redis? How to achieve?

Why is distributed lock needed in Redis? How to achieve?

青灯夜游
青灯夜游forward
2021-10-20 10:37:584348browse

This article will introduce you to distributed locks in Redis, why distributed locks are needed, and how Redis implements distributed locks. I hope it will be helpful to you!

Why is distributed lock needed in Redis? How to achieve?

Why distributed locks are needed

Why distributed locks are needed

Use The purpose of distributed locks is nothing more than to ensure that only one client can operate on shared resources at the same time.

We often encounter concurrency problems when performing logical processing in distributed applications. [Related recommendations: Redis Video Tutorial]

For example, an operation requires modifying the user's status. To modify the status, you need to read the user's status first, modify it in the memory, and then save it back after the modification. . If such operations are performed at the same time, concurrency problems will arise because the two operations of reading and saving state are not atomic.

At this time, distributed locks are used to limit the concurrent execution of the program. As a caching middleware system, redis can provide this kind of distributed lock mechanism.

The essence is to occupy a pit in redis. When other processes want to occupy the pit, they find that they have already occupied the pit. If it is occupied, just wait and try again later

Generally speaking, the distributed locks available in the production environment need to meet the following points:

  • Mutual exclusion, mutual exclusion is the basic feature of the lock. Only one thread can hold the lock at the same time and perform critical operations;
  • Timeout release, timeout release is another necessary feature of the lock, you can Compare the innodb_lock_wait_timeout configuration in the MySQL InnoDB engine to prevent unnecessary thread waiting and resource waste through timeout release;
  • Reentrancy, in a distributed environment, on the same node If the same thread acquires the lock, the request can still be successful again;

Implementation method

Use SETNX to implement

The usage method of SETNX is: SETNX key value. Only when the key key does not exist, the value of the key key is set to value. If the key key exists, SETNX does not take any action. .

boolean result = jedis.setnx("lock-key",true)== 1L;
if  (result) {
    try {
        // do something
    } finally {
        jedis.del("lock-key");
    }
 }

This solution has a fatal problem, that is, after a thread acquires the lock and cannot perform the unlocking operation normally due to some abnormal factors (such as downtime), then the lock will never be released. .

To this end, we can add a timeout period to this lock

The effect of executing SET key value EX seconds is equivalent to executing SETEX key seconds value

The effect of executing SET key value PX milliseconds is equivalent to executing PSETEX key milliseconds value

String result = jedis.set("lock-key",true, 5);
if ("OK".equals(result)) {
    try {
        // do something
    } finally {
        jedis.del("lock-key");
    }
}

The solution looks perfect , but in fact there will still be problems

Just imagine that a certain thread A acquires the lock and sets the expiration time to 10s, and then it takes 15s to execute the business logic. At this time, thread A acquires The lock has already been automatically released by the expiration mechanism of Redis

After thread A acquires the lock and 10 seconds have passed, the changed lock may have been acquired by other threads. When thread A finishes executing the business logic and prepares to unlock (DEL key), it is possible to delete the lock that has been acquired by other threads.

So the best way is to determine whether the lock belongs to you when unlocking. We can set the value to a unique value when setting keyuniqueValue ( It can be a random value, UUID, or a combination of machine number and thread number, signature, etc.).

When unlocking, that is, when deleting the key, first determine whether the value corresponding to the key is equal to the previously set value. If it is equal, the key can be deleted

String velue= String.valueOf(System.currentTimeMillis())
String result = jedis.set("lock-key",velue, 5);
if ("OK".equals(result)) {
    try {
        // do something
    } finally {
      	//非原子操作
	      if(jedis.get("lock-key")==value){
		        jedis.del("lock-key");
        }    
    }
}

We can see the problem at a glance here Come on: GET and DEL are two separate operations. An exception may occur in the gap between GET execution and before DEL execution.

If we only need to ensure that the unlocking code is atomic we can solve the problem

Here we introduce a new method, which is Lua script, the example is as follows :

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

where ARGV[1] represents the unique value specified when setting the key.

Due to the atomicity of the Lua script, during the process of Redis executing the script, other client commands need to wait for the Lua script to be executed before they can be executed.

Ensure that the expiration time is greater than the business execution time

In order to prevent multiple threads from executing business code at the same time, it is necessary to ensure that the expiration time is greater than the business execution time

Add A boolean type attribute isOpenExpirationRenewal, used to identify whether to enable scheduled refresh expiration time

In addition, a scheduleExpirationRenewal method is used to enable the thread to refresh the expiration time

The locking code sets isOpenExpirationRenewal to true after successfully acquiring the lock, and calls the scheduleExpirationRenewal method to start the thread that refreshes the expiration time.

The unlocking code adds a line of code and sets the isOpenExpirationRenewal attribute. If false, stop the thread polling for refreshing the expiration time

Redisson implementation

If the lock is successfully acquired, a scheduled task will be started, and the scheduled task will be checked regularly for renewal

The time difference between each call of this scheduled schedule is internalLockLeaseTime / 3, which is 10 seconds

By default, the locking time is 30 seconds. If the locked business does not After execution, when 30-10 = 20 seconds, a renewal will be performed and the lock will be reset to 30 seconds

RedLock

In the cluster, when the master node hangs up, the slave node will take its place, but there is no obvious perception on the client. It turns out that the first client successfully applied for a lock on the master node, but before the lock could be synchronized to the slave node, the master node suddenly died. Then the slave node becomes the master node. This new node does not have this lock inside, so when another client comes to request a lock, it is approved immediately. This will cause the same lock in the system to be held by two clients at the same time, resulting in insecurity

The Redlock algorithm is to solve this problem

To use Redlock, you need to provide multiple Redis instances. These instances were previously independent of each other and had no master-slave relationship. Like many distributed algorithms, redlock also uses most mechanisms

When locking, it will send set instructions to more than half of the nodes. As long as more than half of the nodesset succeed, the lock is considered successful. . When releasing the lock, a del instruction needs to be sent to all nodes. However, the Redlock algorithm also needs to consider many detailed issues such as error retry and clock drift. At the same time, because Redlock needs to read and write to multiple nodes, it means that the performance of Redis will be lower than that of a single instance.

Redlock algorithm is a high-availability mode introduced on the basis of a single Redis node. Redlock is based on N completely independent Redis nodes, usually an odd number greater than 3 (usually N can be set to 5), which can basically ensure that the cluster Each node will not go down at the same time.

Assuming that the current cluster has 5 nodes, the client running the Redlock algorithm performs the following steps in order to complete the operation of acquiring the lock

  • Client record Current system time, in milliseconds;
  • Try to obtain locks from 5 Redis instances using the same key in sequence. When requesting to obtain a lock from Redis, the client should set a network connection and response timeout. , the timeout should be less than the expiration time of the lock to avoid problems due to network failures;
  • The client uses the current time minus the time to start acquiring the lock to get the time to acquire the lock, if and only if from half The above Redis node acquires the lock, and when the time used is less than the lock expiration time, the lock is successfully acquired;
  • If the lock is acquired, the real effective time of the key is equal to the effective time minus the time used to acquire the lock. time to reduce the chance of timeout;
  • If the lock acquisition fails, the client should unlock it on all Redis instances, even the node where the previous operation request failed, to prevent the server response message from being lost, but Inconsistency caused by successful addition of actual data.

In other words, assuming that the lock expires in 30 seconds and it takes 31 seconds to lock the three nodes, naturally the locking failed

In the Java client officially recommended by RedisRedisson has a built-in implementation of RedLock

https://redis.io/topics/distlock

https:// github.com/redisson/redisson/wiki

RedLock problem:

RedLock only ensures the high availability of the lock, but does not guarantee the correctness of the lock

RedLock is a distributed system that relies heavily on the system clock

Martin’s criticism of RedLock:

  • For efficiency improvement scenarios, RedLock is too heavy.
  • For scenarios that require extremely high accuracy, RedLock cannot guarantee accuracy.

This article is reproduced from: https://juejin.cn/post/7018968452136173576

Author: With a distant heart

More programming related For knowledge, please visit: programming video! !

The above is the detailed content of Why is distributed lock needed in Redis? How to achieve?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete