基於redis的分佈式鎖中的setnx`+`expire`非原子操作問題

基於redis的分佈式鎖, 性能和穩定性都非常好. 但是redis中setnx+expire是非原子操作, 除了用LUA腳本保證實現原子操作, 其實可以直接使用redis自帶的set方法直接實現.

setnx+expire操作過程中, 如果expire無法執行, 會導致死鎖

原生命令格式:

SET key value [EX seconds] [PX milliseconds] [NX|XX]
  • EX seconds : 將鍵的過期時間設置爲 seconds 秒。 執行 SET key value EX seconds 的效果等同於執行 SETEX key seconds value
  • PX milliseconds : 將鍵的過期時間設置爲 milliseconds 毫秒(千分之一秒)。 執行 SET key value PX milliseconds 的效果等同於執行 PSETEX key milliseconds value
  • NX : 只在鍵不存在時, 纔對鍵進行設置操作。 執行 SET key value NX 的效果等同於執行 SETNX key value
  • XX : 只在鍵已經存在時, 纔對鍵進行設置操作

在php的redis擴展中提供的函數的定義是:

    /**
     * Set the string value in argument as value of the key.
     *
     * @since If you're using Redis >= 2.6.12, you can pass extended options as explained in example
     *
     * @param string       $key
     * @param string|mixed $value string if not used serializer
     * @param int|array    $timeout [optional] Calling setex() is preferred if you want a timeout.<br>
     * Since 2.6.12 it also supports different flags inside an array. Example ['NX', 'EX' => 60]<br>
     *  - EX seconds -- Set the specified expire time, in seconds.<br>
     *  - PX milliseconds -- Set the specified expire time, in milliseconds.<br>
     *  - PX milliseconds -- Set the specified expire time, in milliseconds.<br>
     *  - NX -- Only set the key if it does not already exist.<br>
     *  - XX -- Only set the key if it already exist.<br>
     * <pre>
     * // Simple key -> value set
     * $redis->set('key', 'value');
     *
     * // Will redirect, and actually make an SETEX call
     * $redis->set('key','value', 10);
     *
     * // Will set the key, if it doesn't exist, with a ttl of 10 seconds
     * $redis->set('key', 'value', ['nx', 'ex' => 10]);
     *
     * // Will set a key, if it does exist, with a ttl of 1000 miliseconds
     * $redis->set('key', 'value', ['xx', 'px' => 1000]);
     * </pre>
     *
     * @return bool TRUE if the command is successful
     *
     * @link     https://redis.io/commands/set
     */
    public function set($key, $value, $timeout = null)
    {
    }

$redis->set('key', 'value', ['nx', 'ex' => 10]) 表示當key不存在時, 設置key且過期時間爲10秒.

$redis->set('key', 'value', ['nx', 'px' => 500]) 表示當key不存在時, 設置key且過期時間爲500毫秒(即0.5秒).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章