Redis 分布式锁 解决集群环境下屡次定时任务执行

先了解Set参数

SET key value [EX seconds] [PX milliseconds] [NX|XX]html

将字符串值value关联到keynode

若是key 有值, SET 就覆写旧值,无视类型。

对于某个本来带有生存时间(TTL)的键来讲, 当SET命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。redis

可选参数bash

SET
命令的行为能够经过一系列参数来修改:

  • EX second :设置键的过时时间为 second 秒。 SET key value EX second  效果等同  SETEX key second value
  • PX millisecond :设置键的过时时间为 millisecond 毫秒。 SET key value PX millisecond
    效果等同于PSETEX key millisecond value。
  • NX :只在键不存在时,才对键进行设置操做。 SET key value NX  效果等同于  SETNX key value
  • XX :只在键已经存在时,才对键进行设置操做。
返回值:

在 Redis 2.6.12 版本之前, 数据结构

SET
命令老是返回  OK

从 Redis 2.6.12 版本开始,
SET
在设置操做成功完成时,才返回 OK
若是设置了 NX 或者  XX,但由于条件没达到而形成设置操做未执行,那么命令返回空批量回复(NULL Bulk Reply)。

setnx

锁在redis中最简单的数据结构就是string。最先的时候,上锁的操做通常使用setnx,这个命令是当锁不存在的时候set一个val,或许你还会记得使用expire来增长锁的过时,解锁操做就是使用del命令,代码以下:
app

if(redis.setnx('node:lock', 1)){

     redis.expire('node:lock',10);
   // ...todo
    redis.del('node:lock')
}
}复制代码

问题就在于setnx和expire中间若是遇到crash等行为,可能这个lock就不会被释放了
ui

set

为了解决这个问题,咱们能够把超时时间设置跟set操做放在一块儿
spa

if(redis.set('node:lock',1, 'nx', 'ex', 10)){
   // ...todo
    redis.del('node:lock')
}
}复制代码

获取锁的机制是对了,可是删除锁的机制直接使用del是不对的。由于有可能致使误删别人的锁的状况。code

好比,这个锁我上了10s,可是我处理的时间比10s更长,到了10s,这个锁自动过时了,被别人取走了,而且对它从新上锁了。那么这个时候,我再调用del就是删除别人创建的锁了。cdn


终极版:

function lock(lockName,lockTimeout)){
    let lockKey=lockName+':lock';
    let lockValue=new Date().getTime();
    if(redis.set(lockKey,lockValue, 'nx', 'ex', lockTimeout)){
            return lockValue;
    }
    return null;
}


function unlock(lockName, lockValue)){
    let lockKey=lockName+':lock';
    if(redis.get(lockKey)===lockValue){         redis.del(lockName)
            return true;
        }}
复制代码

这里的lockValue是一个时间戳,当lock的时候,往redis的存储这个时间戳,unlock的时候,先get一下lock中的值,若是和我要删除的值是一致的,说明这个锁是以前我set的,不然的话,说明这个锁已通过期,是别人set的,我就不该该对它进行任何操做。

相关文章
相关标签/搜索