基于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秒).
————————————————
版权声明:本文为CSDN博主「aben_sky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/aben_sky/article/details/121515122

posted @ 2022-11-11 11:17  浮尘微光  阅读(1041)  评论(0编辑  收藏  举报