1.考虑的问题点
加锁和解锁的原子性
加锁的超时时间
集群宕机问题
1)加锁过程
redis的命令只有setnx它不包含超时时间的设置,如果我们通过两个命令(setnx expire)来做,就失去了原子性。
庆幸的是我们的连接工具帮我们原子化了两个命令组合的原子性操作了。redisTemplate里面封装好了对应的api
2)加锁的时间
可以设置一个默认时间,同时另起一个线程来动态延长锁的时间
3)加锁的key
一般采用业务相关的key,一般要锁的线程得到的业务key都是相同的
4)对应锁的value
可以采用线程id,uuid,requestid
5) 解锁的过程
首先需要判断是否是自己的锁,也就是先判断锁的value是否和自己的线程id(或者uuid,requestid)相等,再del操作,这里又涉及两个操作的原子性问题。
这时候需要把两个操作写进一个lua脚本里面去
6)锁的重入性问题
前面的过程采用的锁是不可重入的,因为一个线程第二次锁的时候是得不到锁的,这时候就需要改变锁的结构,之前的结构是string,现在需要改成hash结构。
7)集群宕机问题
也就是主节点获取到了锁,但是还没来得及同步到从节点的时候就宕机了。这时候会导致从节点变成新的主节点,但是并没有锁,然后下个线程又获得了锁,导致了
锁的重入,加锁失败。
解决:redlock,实现思路是我给同时多个redis集群或者redis单机加锁,然后我获取锁也从多个实例上去获取,但是也要设置获取的时间防止获取锁时间过长。如果我
得到大于半数的实例返回获取锁成功,就认为成功。redlock的实现过程redisson已经帮我们封装好了,有空可以去研究下。
也就是hset(key,uuid,1)每次上锁就是把最后的1加1,解锁就是减1.最后判断最终结果是1就del掉。当然这些操作也都需要封装到lua脚本里面去。
另外需要关注一个框架redission,它里面封装好了上面一套的实现过程。
原文:https://www.cnblogs.com/johnzhao/p/14698673.html