Examples of several ways in which redis implements locking are explained in detail

  • 2020-05-30 21:17:05
  • OfStack

preface

This article mainly introduced several methods about redis lock implementation, to share out for your reference learning, the following words do not say, to 1 look at the detailed introduction.

1. redis lock sorting

The list of locking commands that redis can use is INCR, SETNX, and SET

2. Type 1 lock command INCR

The idea behind this locking is that if key does not exist, the value of key will be initialized to 0 before the INCR operation is performed to increment by 1.
Then when another user performs an INCR operation to add 1, if the number returned is greater than 1, the lock is in use.

1. The client A requests the server to obtain the lock if the value of key is 1

2. The client B also requests the server to obtain the key value of 2, which indicates that the acquisition of the lock failed

3. The client A execution code is completed to delete the lock

4. After waiting for 1 period of time, the client B gets the value of key to be 1 when making the request

5. The client B executes the code and removes the lock


 $redis->incr($key);
 $redis->expire($key, $ttl); // Set the build time to 1 seconds 

3. The second type of lock SETNX

The idea behind this locking is to set key to value if key does not exist

If key already exists, SETNX does nothing

1. The client A requests the server to set the value of key. If the setting is successful, it means that the lock is successfully added

2. The client B also asks the server to set the value of key. If it fails to return, it means that it failed to lock

3. The client A executes the code and removes the lock

4. After waiting for 1 period of time, the client B requested to set the value of key, and the setting was successful

5. The client B execution code is completed to delete the lock


  $redis->setNX($key, $value);
  $redis->expire($key, $ttl);

4. Third type of lock SET

There is a problem with both methods, and you will find that you need to set key to expire. So why set key to expire? If the request execution exits accidentally for some reason, causing the lock to be created but not removed, the lock will remain 1 forever so that the cache will never be updated again. So we need to add an expiration date to the lock in case something happens.

But setting with Expire is not an atomic operation. You can also use transactions to ensure atomicity, but there are still some issues, so the official reference was made to another command, SET, which itself has included the ability to set expiration times since version 2.6.12.

1. The client A requests the server to set the value of key. If the setting is successful, it means that the lock is successful

2. The client B also requests the server to set the value of key. If the client B fails, it means that it failed to lock

3. The client A executes the code and removes the lock

4. After waiting for 1 period of time, the client B requested to set the value of key, and the setting was successful

5. The client B executes the code and removes the lock


  $redis->set($key, $value, array('nx', 'ex' => $ttl)); //ex Said second 

5. Other questions

Although step 1 has satisfied our requirements, there are other issues to consider.

1. What if redis finds that the lock has failed? Interrupt request or loop request?

2. If one of them gets the lock, is it easy to grab the lock when the others get the lock?

3. After the lock expires in advance, the client A has not finished executing, and the client B has acquired the lock. At this time, the client A has finished executing, will you delete the lock of B when you delete the lock?

6. Solutions

For problem 1: use the loop request, the loop request to acquire the lock

For problem 2: for problem 2, when the loop requests to acquire the lock, add the sleep function and wait for a few milliseconds before executing the loop

For problem 3: the key stored during locking is random. In this way, every time you delete key, determine whether the value stored in key is the same as the value stored by yourself


    do { // For the problem 1 , using the loop 
      $timeout = 10;
      $roomid = 10001;
      $key = 'room_lock';
      $value = 'room_'.$roomid; // distribution 1 There are three random values for the problem 3
      $isLock = Redis::set($key, $value, 'ex', $timeout, 'nx');//ex  seconds 
      if ($isLock) {
        if (Redis::get($key) == $value) { // Prevent premature expiration, mistakenly delete the other request to create the lock 
          // Executing internal code 
          Redis::del($key);
          continue;// Successfully executed delete key And get out of the loop 
        }
      } else {
        usleep(5000); // Sleep, reduce the frequency of snatching, relieve redis Stress, focus on the problem 2
      }
    } while(!$isLock);

7. Another lock

The above locks fully meet the requirements, but the authorities also provide a set of locking algorithm, PHP here for example


  $servers = [
    ['127.0.0.1', 6379, 0.01],
    ['127.0.0.1', 6389, 0.01],
    ['127.0.0.1', 6399, 0.01],
  ];
  
  $redLock = new RedLock($servers);
  
  // lock 
  $lock = $redLock->lock('my_resource_name', 1000);
  
  // Remove the lock 
  $redLock->unlock($lock)

The above is a lock method provided by the authorities, which is similar to general method 1 of the sixth method, except that it is more robust. So you can call it directly using the class methods that are officially provided. The authorities provide various languages for implementing locks.

conclusion


Related articles: