Redis proper use of the locking mechanism to achieve SETNX

setNX, is set if not exists acronym, that is, only when it does not exist is set, returns 1 set successfully, 0 if setup fails. We can use it to achieve the effect of the lock, but many people have not taken into account some of the problems in the use of the process.
For example, an interface to query the database because it is larger than the refresh request the addition of cache, and the cache expires after setting. When concurrency than the larger and cache expires the moment, a large number of concurrent requests will query the database directly cause an avalanche. If you use a lock mechanism to control only one request to update the cache will be able to avoid an avalanche of problems. The following is a method for locking a lot of people think subconsciously

RS = redis- $ $> SETNX (Key $, $ value); 
IF ($ RS) { 
    // update the cache processing logic 
    // ...... 
    // remove lock 
    $ redis-> del ($ key) ; 
}

  By acquiring the lock setNX, if successful then update the cache and then remove the lock. In fact, there is a serious problem: If you update the cache when for some reason unexpectedly quit, then the lock will not be and there has been deleted, so that the cache never get updated. To solve this problem one might think to lock a set expiration date, as follows

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

  Because setNX not have set the expiration time of the function, so to help Expire to set up, at the same time need to use Multi / Exec to ensure atomicity request, so as not to setNX succeeded Expire failed. This also has a problem: When multiple requests arrive, although only one request setNX can be successful, but they are nothing but any request Expire can be successful, which means that even if you can not obtain the lock also set the expiration time, the lock has been lead effective, still can not solve the above problem. Obviously setNX can not meet demand, Redis from 2.6.12 onwards, covering SETEX SET function, SET itself but also contains the expiration time set function, so you can use the SET solve the above problems encountered

RS = redis- $ $> SET (Key $, $ value, Array ( 'NX', 'EX' => $ TTL)); 
IF ($ RS) { 
    // update the cache processing logic 
    @ ..... . 
    // delete lock 
    $ redis-> del ($ Key); 
}

  At this point it is still a problem, update the cache if a time longer than the validity of the request lock, resulting in the lock cache update process becomes ineffective, then the request will get to another lock, but a previous request updated in the cache when the lock, then it will delete erroneous deletion of the request to create another lock appears. So to avoid this problem, the need to introduce a random value when creating the lock and remove the lock to be judged at the time

RS = redis- $ $> SET (Key $, $ Random, Array ( 'NX', 'EX' => $ TTL)); 
IF ($ RS) { 
     // update the cache processing logic 
    @ ..... . 
    // first determine the random number, is the same lock is deleted 
    IF ($ redis-> GET (Key $) random == $) { 
        $ redis-> del (Key $); 
    } 
}

  

Guess you like

Origin www.cnblogs.com/zh718594493/p/12111417.html