使用redis的setNX
命令,setNX的特性是这样的,当一个线程进来往redis中通过setNX去存储一个值的时候,比如说小明这个键没有值的时候,它会往里面存一个值,然后返回true,然后又一个线程来往小明这个键里通过setNX存储一个值的时候,发现有值,此时就会返回false。
因此,当一个用户请求进来的时候,通过setNX来设置一个键(值随意),当里面没有值的时候,返回true,加锁成功,加上过期时间
,其他请求再来的时候发现无法上锁了,只能进行等待了。释放锁使用delete操作。
SET xiaoming_lock unique_value NX EX 10
- xiaoming_lock 是锁的键。
- unique_value 是一个唯一的值,可以使用当前时间戳或者 UUID。
- NX 表示仅在键不存在时设置键。
- EX 表示设置键的过期时间,单位是秒,此处为 10 秒。
但是这样还会有问题,比如当业务的处理时间超过了这把锁的过期时间,业务还没有处理完,锁却已经过期了,其他的线程就会趁虚而入,而线程1处理完了之后呢,此时释放的是线程2的锁,其他线程再趁虚而入,以此类推,从而又会造成超卖的问题。
存在两个问题
1.业务没处理完,锁过期了
2.在第一个问题的基础上,由于其他线程的趁虚而入导致释放了其他线程的锁
解决方案
针对第一个问题,添加一个子线程,每过几秒去确认主线程是不是在线,在线就将过期时间重置,即锁续命。
针对第二个问题,给锁加一个唯一的uuid,这样能保证每一把锁的key绑定的是自己的线程,从而不会去释放别的线程的锁。
Redisson
redis提供了Redisson组件来完成了上面的功能。
Redisson存在的问题
使用Redisson也会有问题:如果你的redis使用了主从集群的模式,比如主节点挂了,从节点还没同步到,还是会发生超卖等问题。
redlock
解决方案:
使用redlock解决,redlock会针对redis中的所有的节点来进行同步,若没有使用redlock,它会将锁存到主节点,主节点存完就会立马响应,使用redlock的话,它保证了所有的节点都存储完毕了,才会返回存储成功响应,这样就能保证了强一致性。