Research on the scheme of realizing distributed lock on Redis to improve performance _redis

Source: Internet
Author: User
Tags redis

Background:

In many applications of Internet products, some scenes need to be locked, such as: Second Kill, global increment ID, floor build and so on. Most of the solutions are based on DB, Redis for single process single-threaded mode, using queue mode to turn concurrent access into serial access, and there is no competitive relationship between multiple clients for Redis connections.

Project Practice

The task queue uses the distributed lock the situation to be more, in the business logic can handle asynchronously the operation to put in the queue, in other threads processing after the team, at this time uses the distributed lock in the queue, guarantees the team and the brigade's consistency. As for the logical analysis of the Redis queue, I'll summarize it next time, skipping over here first.


The following is a detailed analysis and understanding of the logical Code of the distributed locks implemented by Redis:

1, in order to avoid special reasons for the lock can not be released, after the lock is successful, the lock will be given a lifetime (through the lock method parameters set or use the default value), the lock will be automatically released beyond the lifetime.

2, the lock's survival time default relatively short (second level, see the Lock method), so if it takes a long time to lock, you can extend the life of the lock through the expire method to the appropriate time. Like calling expire within a loop.
3, System-level lock when the process for any reason appear crash, the operating system will recycle the lock itself, so there will be no loss of resources.
4, but the distributed lock is different. If a long time is set, once the unlock has not been invoked for a variety of reasons process crash or other exceptions, the lock becomes a garbage lock for the remainder of the time, causing the other processes or processes to reboot and then fail to enter the lock area.

<?php require_once ' redisfactory.php ';
  /** * implemented on Redis distributed lock/class Redislock {//single case mode private static $_instance = null;
    public static function instance () {if (self::$_instance = = null) {self::$_instance = new Redislock ();
  return self::$_instance;
  
//redis object variable private $redis;
 
  An array of symbol names to store the lock is private $lockedNames = Array (); 
  The Public Function __construct () {//Gets a redisstring instance $this->redis = Redisfactory::instance ()->getstring (); /** * Lock * * @param the identity name of the string lock * @param int Gets the wait timeout (in seconds) for the lock to fail, and will try to acquire the lock until the timeout time. 0 indicates that the maximum lifetime (in seconds) of the current lock must be greater than 0 when the failure is returned directly without waiting for the @param int. If the lock is not freed after the lifetime is exceeded, the system automatically forces its release * @param the interval (microseconds) of the pending retry after the failure of the int acquire the lock (microsecond)/Public Function lock ($name, $timeout = 0, $expir
 
    E =, $waitIntervalUs = 100000) {if (empty ($name)) return false;
    $timeout = (int) $timeout;
    $expire = max ((int) $expire, 5);
    $now = Microtime (true);
    $timeoutAt = $now + $timeout; $expirEAt = $now + $expire;
    $redisKey = "Lock: $name";
      while (true) {$result = $this->redis->setnx ($redisKey, (string) $expireAt);
        
if ($result!== false) {//Set lifetimes for $rediskey $this->redis->expire ($redisKey, $expire);
        The maximum survival time is recorded in an array $this->lockednames[$name] = $expireAt;
      return true;
      
///In seconds, returns the remaining lifetime of the $rediskey $ttl = $this->redis->ttl ($redisKey); A TTL of less than 0 indicates that no lifetime is set on the key (key does not exist because the SETNX is created automatically)//If this happens, the process crash after a successful instance setnx the following expire is not Call.
        At this point, you can set the expire directly and lock the->redis->set if ($ttl < 0) {$this ($redisKey, (String) $expireAt, $expire);
        $this->lockednames[$name] = $expireAt;
      return true;
 
      
/Set no wait or timeout if ($timeout <= 0 | | microtime (TRUE) > $timeoutAt) break;
    Hang up for some time and try Usleep ($waitIntervalUs);
  return false;
  /** * Increases the specified lifetime (in seconds) for the current lock and must be greater than 0
* * @param string Lock's identity name * @param int Lifetime (sec), must be greater than 0/public function expire ($name, $expire) {if ($this-
      >islocking ($name)) {if ($this->redis->expire ("Lock: $name", Max ($expire, 1)) {return true;
  return false; /** * Determines whether the current lock with the specified name * * @param mixed $name/Public function islocking ($name) {if isset ($this- >lockednames[$name])) {return (string) $this->lockednames[$name] = = (string) $this->redis->get ("Lock: $na
    Me ");
  return false; /** * Release Lock * * @param the identity name of the string lock/Public function unlock ($name) {if ($this->islocking ($name
        ) {if ($this->redis->deletekey ("Lock: $name")) {unset ($this->lockednames[$name]);
      return true;
  return false;
    /** frees all locks that are currently acquired/Public function Unlockall () {$allSuccess = true; foreach ($this->lockednames as $name => $item) {if (false = = = $this->Unlock ($name)) {$allSuccess = false;
  } return $allSuccess;
 }
}

A lot of this code is written with annotations, so it's easy to understand how to implement a distributed lock in Redis, if you take it seriously.

Related Article

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.