Redis Distributed Lock--PHP

The Role of Redis Distributed Locks

In a stand-alone environment, there is a second-kill commodity activity, in a short time, server pressure and traffic will rise sharply. This will lead to concurrency problems. If you want to solve concurrency, you need to solve it.

1. Improving system throughput, that is, requests processed by qps per second
2. Avoid the problem of over-buying and over-buying caused by resource competition in the case of high concurrency of commodities.

Solution 1: Improving the qps of the system by using memory database
Problem 2: We need to use locks we often encounter, such as MySQL read locks, write locks, exclusive locks, pessimistic locks, optimistic locks. But here we only discuss redis to implement locks

Simple Version Setup Lock

$redis = new Redis();
$redis->connect('127.0.0.1', 6379); //Connect Redis

$expire = 10;//Valid for 10 seconds
$key = 'lock';//key
$value = time() + $expire;//Lock value = Unix timestamp + lock validity
$lock = $redis->setnx($key, $value);
//If the lock is successful, the next step is performed.
if(!empty($lock))
{
//Next step operation..       
}

If you can solve all the problems by setting locks in such a simple version, it would be too trivial to see the application of locks in programs.

This is basically the way the normal operation examples are written. But there are some problems with this writing.

1. If 10,000 requests access keys that redis does not exist, then the request means that MySQL data has been received, resulting in 100% or even downtime of CPU in a short time. This scenario is commonly referred to as cache avalanche caused by cache breakdown.
2. If the CPU is too high or the network delay problem causes the lock not to be deleted or the cache key expires not to be recycled, a deadlock will be formed.

Solution: The purpose of referring to reids setnx method is to set a new value when the key set does not exist. This avoids the problem of cache breakdown. Detecting key expiration time to avoid deadlock

Deadlock Solution

    $expire = 10;//Valid for 10 seconds
    $key = 'lock';//key
    $value = time() + $expire;//Lock value = Unix timestamp + lock validity
    $status = true;
    while($status)
    {
        $lock = $redis->setnx($key, $value);
        if(empty($lock))
        {
            $value = $redis->get($key);
            if($value < time())
            {
                $redis->del($key);
            }       
        }else{
            $status = false;
            //Next step...
        }
    }

1. It is reasonable to say that there is no big problem in solving the competition problem of single-machine version locks. Then the special case arises, if the key setting the lock is not deleted due to unexpected circumstances, so there will also be deadlock.

2. In the distributed cluster business scenario, each server exists independently. How can multiple servers compete for locks through an identity? Distributed locks are used here.

Here is a brief introduction to MYSQL transaction mechanism to extend. Transaction has four characteristics: ACID, which has four isolation levels: commit read, commit read, repeatable read, serialization. These features only work on a single server. When it comes to distributed cluster, data on different servers, it is difficult to maintain dataThe same is true for consistency and isolation close to transactions, so the role of transactions is not significant. Redis.

Correct Opening Mode of Distributed Lock

   /**
     * Implementing Redis Distributed Lock
     */
    $key        = 'demo';       //Cache KEY to update information
    $lockKey    = 'lock:'.$key; //Set lock KEY
    $lockExpire = 10;           //Set the validity of the lock to 10 seconds
     
    //Getting Cache Information
    $result = $redis->get($key);
    //Determine whether there is data in the cache
    if(empty($result))
    {
        $status = TRUE;
        while ($status)
        {
            //Set the lock value to the current timestamp + expiry date
            $lockValue = time() + $lockExpire;
            /**
             * Create lock
             * An attempt was made to create a cache with $lockKey as the key, value being the current timestamp
             * Because the setnx() function will only succeed if there is no cache for the current key
             * Therefore, this function can be used to determine whether the current operation has been executed by other processes.
             * @var [type]
             */
            $lock = $redis->setnx($lockKey, $lockValue);
            /**
             * Operations can be performed if one of the two conditions is satisfied.
             * 1,The lock was successfully created in the previous step.
             * 2,   1)Determine whether the value of the lock (timestamp) is less than the current time $redis - > get ()
             *      2)At the same time, a new value of $redis - > GetSet () is set successfully for the lock.
             */
            if(!empty($lock) || ($redis->get($lockKey) < time() && $redis->getSet($lockKey, $lockValue) < time() ))
            {
                //Set lifetime for locks
                $redis->expire($lockKey, $lockExpire);
                //******************************
                //Insert and update the cache operation here.
                //******************************
     
                //Delete the lock after the above procedure has finished
                //Check if the lock is expired, there is no need to delete the expired lock
                if($redis->ttl($lockKey))
                    $redis->del($lockKey);
                $status = FALSE;
            }else{
                /**
                 * If there is a valid lock, do the corresponding processing here.
                 *      Wait for the current operation to complete before executing the request
                 *      Direct return
                 */
                sleep(2);//Wait 2 seconds before attempting to perform the operation
            }
        }
    }

Ending

This article is different from other blog articles from the breadth of knowledge (mysql), the advantages and disadvantages of the sample code and the application scenarios. Hey hey!

Keywords: PHP Redis MySQL Unix network

Added by Drebin on Thu, 16 May 2019 01:18:22 +0300