How to use Redis locks to solve high concurrency problems

Source: Internet
Author: User
Tags redis
High concurrency is a problem we often encounter, so how can we solve this problem of high concurrency? This article describes the use of Redis locks to solve high concurrency problems, come together to see it.

Here we mainly use Redis's SETNX command to handle high concurrency.

The SETNX has two parameters. The first parameter represents a key. The second parameter represents a value. If the current key does not exist, the current key is inserted and the second parameter is a value. Returns 1. If the current key is present, 0 is returned.

Create an inventory table

CREATE TABLE `storage` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `number` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

Set initial inventory to 10

Create Order Form


CREATE TABLE `order` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `number` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1


Testing when no locks are used

$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
$sql="select `number` from storage where id=1 limit 1";
$res = $pdo->query($sql)->fetch();
$number = $res['number'];
If($number>0)
{
     $sql ="insert into `order` VALUES (null,$number)";
      $order_id = $pdo->query($sql);
     If($order_id)
     {
         $sql="update storage set `number`=`number`-1 WHERE id=1";
         $pdo->query($sql);
     }
}

The AB test simulates concurrency and finds that the inventory is correct.

mysql> select * from storage;
+----+--------+
| id | number |
+----+--------+
|  1 |      0 |
+----+--------+
1 row in set (0.00 sec)

Look at the order form.


mysql> select * from `order`;
+----+--------+
| id | number |
+----+--------+
|  1 |     10 |
|  2 |     10 |
|  3 |      9 |
|  4 |      7 |
|  5 |      6 |
|  6 |      5 |
|  7 |      5 |
|  8 |      5 |
|  9 |      4 |
| 10 |      1 |
+----+--------+
10 rows in set (0.00 sec)


It is found that there are several orders that are the same inventory data for the operation, which can lead to oversold situations.

Modify code to join Redis lock for Data control

<?php
/**
 * Created by PhpStorm.
 * User: daisc
 * Date: 2018/7/23
 * Time: 14:45
 */
Class lock
{
    Private static $_instance ;
    Private $_redis;
    Private function __construct()
    {
        $this->_redis = new Redis();
        $this->_redis ->connect('127.0.0.1');
    }
    Public static function getInstance()
    {
        If(self::$_instance instanceof self)
        {
            Return self::$_instance;
        }
        Return self::$_instance = new self();
    }
 
    /**
     * @function lock
     * @param $key lock name
     * @param $expTime expiration time
      */
    Public function set($key,$expTime)
    {
        / / Initial lock
        $isLock = $this->_redis->setnx($key,time()+$expTime);
        If($isLock)
        {
            Return true;
        }
        Else
        {
            //In case of locking failure. Determine if the lock already exists. If the latch has expired, delete the lock. Relock
            $val = $this->_redis->get($key);
            If($val&&$val<time())
            {
                $this->del($key);
            }
            Return $this->_redis->setnx($key,time()+$expTime);
        }
    }
 
     /**
     * @param $key unlock
     */
    Public function del($key)
    {
        $this->_redis->del($key);
    }
 }
 
 $pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');
$lockObj = Lock::getInstance();
/ / Judge is able to lock successfully
If($lock = $lockObj->set('storage',10))
{
    $sql="select `number` from storage where id=1 limit 1";
    $res = $pdo->query($sql)->fetch();
    $number = $res['number'];
    If($number>0)
    {
        $sql ="insert into `order` VALUES (null,$number)";
 
        $order_id = $pdo->query($sql);
        If($order_id)
        {
             $sql="update storage set `number`=`number`-1 WHERE id=1";
            $pdo->query($sql);
        }
    }
    //Unlock
    $lockObj->del('storage');

 }
Else
{
    //The lock does not succeed in performing other operations.
}

Test again toabsee the test results


mysql> select * from `order`;
+----+--------+
| id | number |
+----+--------+
|  1 |     10 |
|  2 |      9 |
|  3 |      8 |
|  4 |      7 |
|  5 |      6 |
|  6 |      5 |
|  7 |      4 |
|  8 |      3 |
|  9 |      2 |
| 10 |      1 |
+----+--------+
10 rows in set (0.00 sec)


The Discovery Order table does not operate on the same inventory data condition. Therefore, the use of Redis locks can effectively handle high concurrency.

Here in the lock when you can actually do not need to determine the expiration time, here we to avoid causing deadlocks, so add an expiration time judgment. The lock is actively deleted when it expires.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.