PHP restricts concurrent access to classes using Redis lock

Source: Internet
Author: User


1. Concurrent access restriction issues


For scenarios where concurrent access is restricted to the same user, users can request multiple requests successfully if the user requests multiple times and the server handles no lock limit.

For example, redemption coupons, if the user at the same time and the exchange of the code, without the lock limit, the user can use the same redemption code at the same time to redeem a number of coupons.

The pseudo code is as follows:

If A (can be changed)    B (perform redemption)    C (update to redemption) D (end)

If the user carries out the interchange code, it can be judged by the redemption (a), since a redemption (B) must be performed before it is updated to the Redemption (C). Therefore, if the user has a number of requests before an update to a redemption, these requests can be executed successfully.

2. Concurrent Access Throttling methods

The use of file locks allows for concurrent access restrictions, but for distributed architecture environments, using file locks does not guarantee concurrent access restrictions for multiple servers.

Redis is an open source API that is written in ANSI C, supports the web, can be persisted in memory, key-value databases, and provides multiple languages.
This article uses its Setnx method to implement the distributed lock function. setnx is Set it Not eXists.
Insert succeeds when key value does not exist (acquires lock succeeds), insert fails if key value already exists (get lock failed)

redislock.class.php

<?php/** * Redis lock Operation class * date:2016-06-30 * author:fdipzone * ver:1.0 * * FUNC: * Public lock get lock * Pub    LIC unlock release lock * Private Connect connection */class Redislock {//class start Private $_config;    Private $_redis; /** * Initialize * @param Array $config redis Connection Settings */Public function __construct ($config =array ()) {$this-&G        T;_config = $config;    $this->_redis = $this->connect (); }/** * Get lock * @param String $key Lock ID * @param Int $expire Lock Expiry time * @return Boolean */P        ublic function Lock ($key, $expire =5) {$is _lock = $this->_redis->setnx ($key, Time () + $expire);            Cannot get lock if (! $is _lock) {//Determine if the lock expires $lock _time = $this->_redis->get ($key);                Lock expired, delete lock, retrieve if (time () > $lock _time) {$this->unlock ($key);            $is _lock = $this->_redis->setnx ($key, Time () + $expire); }} return $is _locK?    True:false; }/** * Release lock * @param String $key Lock identifier * @return Boolean/Public Function unlock ($key) {RET    Urn $this->_redis->del ($key); /** * Create redis connection * @return Link */Private Function connect () {try{$redis = new Redi            S ();            $redis->connect ($this->_config[' host '), $this->_config[' Port '], $this->_config[' timeout ',                        $this->_config[' reserved '), $this->_config[' retry_interval ']);            if (Empty ($this->_config[' auth ')) {$redis->auth ($this->_config[' auth ']);        } $redis->select ($this->_config[' index ');                    }catch (Redisexception $e) {throw new Exception ($e->getmessage ());        return false;    } return $redis; }}//Class end?>

demo.php

<?phprequire ' RedisLock.class.php '; $config = Array (    ' host ' = ' localhost ',    ' port ' = 6379,    ' Index ' = 0,    ' auth ' + ', '    timeout ' = 1,    ' reserved ' = NULL,    ' retry_interval ' and 100, ;//Create Redislock Object $oredislock = new Redislock ($config);//define lock identity $key = ' mylock ';//get lock $is_lock = $oRedisLock->lock ($key , if ($is _lock) {    echo ' get lock success<br> ';    Echo ' do sth. <br> ';    Sleep (5);        Echo ' success<br> ';        $oRedisLock->unlock ($key);    Get lock failed    }    else{        echo ' request too frequently<br> '; >



test method:
Open two different browsers while accessing demo.php in A/b
If the first access will get to the lock
Output
Get lock success
Do sth.
Success

Another acquisition lock failure will output the request too frequently

Ensure that only one access is valid at the same time, effectively restricting concurrent access.


to avoid a sudden system error that results in a deadlock, an expiration time is added when the lock is acquired, and if the expiration time is exceeded, the lock is released even if it is locked, avoiding the problem caused by the deadlock.


SOURCE Download Address: Click to view

1. Concurrent access restriction issues

For scenarios where concurrent access is restricted to the same user, users can request multiple requests successfully if the user requests multiple times and the server handles no lock limit.

For example, redemption coupons, if the user at the same time and the exchange of the code, without the lock limit, the user can use the same redemption code at the same time to redeem a number of coupons.

The pseudo code is as follows:

If A (can be changed)    B (perform redemption)    C (update to redemption) D (end)

If the user carries out the interchange code, it can be judged by the redemption (a), since a redemption (B) must be performed before it is updated to the Redemption (C). Therefore, if the user has a number of requests before an update to a redemption, these requests can be executed successfully.

2. Concurrent Access Throttling methods

The use of file locks allows for concurrent access restrictions, but for distributed architecture environments, using file locks does not guarantee concurrent access restrictions for multiple servers.

Redis is an open source API that is written in ANSI C, supports the web, can be persisted in memory, key-value databases, and provides multiple languages.
This article uses its Setnx method to implement the distributed lock function. setnx is Set it Not eXists.
Insert succeeds when key value does not exist (acquires lock succeeds), insert fails if key value already exists (get lock failed)

RedisLock.class.php

<?php/** * Redis lock Operation class * date:2016-06-30 * author:fdipzone * ver:1.0 * * FUNC: * Public lock get lock * Pub    LIC unlock release lock * Private Connect connection */class Redislock {//class start Private $_config;    Private $_redis; /** * Initialize * @param Array $config redis Connection Settings */Public function __construct ($config =array ()) {$this-&G        T;_config = $config;    $this->_redis = $this->connect (); }/** * Get lock * @param String $key Lock ID * @param Int $expire Lock Expiry time * @return Boolean */P        ublic function Lock ($key, $expire =5) {$is _lock = $this->_redis->setnx ($key, Time () + $expire);            Cannot get lock if (! $is _lock) {//Determine if the lock expires $lock _time = $this->_redis->get ($key);                Lock expired, delete lock, retrieve if (time () > $lock _time) {$this->unlock ($key);            $is _lock = $this->_redis->setnx ($key, Time () + $expire); }} return $is _locK?    True:false; }/** * Release lock * @param String $key Lock identifier * @return Boolean/Public Function unlock ($key) {RET    Urn $this->_redis->del ($key); /** * Create redis connection * @return Link */Private Function connect () {try{$redis = new Redi            S (); $redis->connect ($this->_config[' host '), $this->_config[' Port ', $this->_config[' timeout '                        ], $this->_config[' reserved '), $this->_config[' retry_interval ']);            if (Empty ($this->_config[' auth ')) {$redis->auth ($this->_config[' auth ']);        } $redis->select ($this->_config[' index ');                    }catch (Redisexception $e) {throw new Exception ($e->getmessage ());        return false;    } return $redis; }}//Class end?>

demo.php

<?phprequire ' RedisLock.class.php '; $config = Array (    ' host ' = ' localhost ',    ' port ' = 6379,    ' Index ' = 0,    ' auth ' + ', '    timeout ' = 1,    ' reserved ' = NULL,    ' retry_interval ' and 100, ;//Create Redislock Object $oredislock = new Redislock ($config);//define lock identity $key = ' mylock ';//get lock $is_lock = $oRedisLock->lock ($key , if ($is _lock) {    echo ' get lock success<br> ';    Echo ' do sth. <br> ';    Sleep (5);        Echo ' success<br> ';        $oRedisLock->unlock ($key);    Get lock failed    }    else{        echo ' request too frequently<br> '; >



test method:
Open two different browsers while accessing demo.php in A/b
If the first access will get to the lock
Output
Get lock success
Do sth.
Success

Another acquisition lock failure will output the request too frequently

Ensure that only one access is valid at the same time, effectively restricting concurrent access.


to avoid a sudden system error that results in a deadlock, an expiration time is added when the lock is acquired, and if the expiration time is exceeded, the lock is released even if it is locked, avoiding the problem caused by the deadlock.


The above is PHP using Redis lock limit concurrent access to the content of the class, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • 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.