耐心看完,我相信你会有收获
一:什么事分布式锁?
百度如上,简单回答就是不同系统系统之间同步获取共享资源打的一种方式
二:首先需要知道的是,分布式锁需要解决的问题是什么?
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出现卡顿的情况,如果你在这里还有更加好的方法来解决,或者可以直接与我讨论