为什么要用分布式锁
如果原本我们的系统分布在一台机器上的时候,JVM提供的锁就能解决并发问题。但是如果我们是使用多台机器,要同时去Redis里面去拿同一个Key 这个时候,就会发生并发问题,因为这个时候JVM的锁事无
法解决这个问题。
基于Redis的分布式锁
-
加锁:最简单的方法是使用setnx 命令,Key 是锁的唯一标识
setnx key value
:是去redis尝试set,如果里面已经有key,那么就设置失败返回0
这里其实就是利用的redis的原子性,实现了CAS的效果。 -
解锁:有加锁就得有解锁。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简单方式是执行
del
指令del key
:删去Key 达到解锁的效果 -
锁超时:
因为如果宕机 不给锁设置超时,那么就会死锁 ,所以在 setnx的时候需要设置超时时间。expire key times
-
问题!
- 第一点: 在加锁和锁超时的时候 不是原子操作
- 解决方案:可以利用lua ,set 可以添加可选参数
- del 误删:如果某个业务逻辑的时间超过了超时时间,这个时候如果key 已经被删除了就会有第二个逻辑进来操作 从而没有达到锁的效果。
- 解决方案:使用守护线程 一直去给我们的key 加上超时时间,这样会让锁不被释放。
- 守护线程:开辟一个线程 如果主线程挂了或者结束 那么守护线程也会结束。
- 解决方案:使用守护线程 一直去给我们的key 加上超时时间,这样会让锁不被释放。
- 第一点: 在加锁和锁超时的时候 不是原子操作
Redission
tryLock()
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hset', KEYS[1], ARGV[2], 1);
redis.