redis 基于SETNX和EXPIRE的用法 实现redis 分布式锁

耐心看完,我相信你会有收获

一:什么事分布式锁?

百度如上,简单回答就是不同系统系统之间同步获取共享资源打的一种方式

二:首先需要知道的是,分布式锁需要解决的问题是什么?
    1.互斥性:任一时刻是有一个客户端获取锁,不能两个客户端获取到锁
    2.安全性:锁只能被持有该客户端的删除,不能由其他客户端删除
    3.死锁:一个客户端获取到锁,导致宕机,而其他客户端无法获取到资源
    4.容错:一些节点宕机,客户端任然能获取锁和释放锁

三.实现原理;
    redis有一个指令:SETNX key value:如果key不存在,则创建并赋值
    指令返回:设置成功,返回1,设置失败 返回0

如上图所示,为了测试方便我在windows 上操作,由于setnx 是原子性的,也就是当我们在操作代码的业务逻辑的时候可以给某key设值,成功返回返回1,上图操作也可以看出,设置成功后不能修改,get 到的还是test,也就是当我们设置成功后,我们线程可以去执行该段业务逻辑

那么问题来了,如何解决SETNX长期有效的问题?

    redis 提供了一个指令:EXPIRE key seconds
          设置key 的生存时间,当key过期(生存时间为0),会自动删除

如下图所示:

设置两秒钟的时间,可以看出再次setnx locknx task ,返回为1,说明执行过期时间生效,如下如简单代码:

RedisService redisService = SpringUtils.getBean(RedisService.class)
long status = redisService,setnx(key,"1")
if(status == 1){
  redisService.expire(key,expire)
  //执行独占资源的业务逻辑
}

上述思路问题是可以解决问题,但是很明显会出现一个问题?
       思考一下就可以想到,当我们设置了SETNX后,如果马上挂掉了,那我们再次    EXPIRE 指令是不是就会无法生效,出现了资源锁死的情况,独占资源所以针对这样问题redis 在2.6.12版本过后,有了一个新的决绝方案

SET key value [EX seconds] [PX millisecounds] [NX|XX]
EX seconds:设置键的过期时间为second秒
PX millisecounds:设置键的过期时间为millisecounds 毫秒
NX:只在键不存在的时候,才对键进行设置操作
XX:只在键已经存在的时候,才对键进行设置操作
SET操作成功后,返回的是OK,失败返回NIL

如图所示,

我再redis里面存储了一个 locktarget 的值为 12345,执行成功后我马上修改,返回时间为nil 失败,等过10后再次执行返回ok,这样就可以很轻松决绝当我们执行SETNX的时候服务挂掉,资源独占的情况,伪代码可以参见如下图:

RedisService redisService = springUtils.getBean(RedisService.class)
String result = redisService.set(lockKey,requestId,SET_IF_NOT_EXIT,SET_WHIT_EXPIRT_TIME,expireTime);
    if("ok".equals(result)){
          //执行独占资源的业务逻辑
}

如果需要大批量设置过期时间,网上给出的找到答案是,在key上给一个随机值,来避免redis出现卡顿的情况

猜你喜欢

转载自blog.csdn.net/CoreyXuu/article/details/89019869