redis-分布式锁注意事项

多jar包单redis

lockKey:商品标识
value:当前线程标识

1.确保每把锁同一时间能且仅能上一次
setnx(set if not exists):当锁不存在时才上锁
redisTemplate.opsForValue().setIfAbsent(lockKey,value)
没加上锁需要返回错误码 直接让其重试

2.上锁成功后,需要在之后将锁释放
redisTemplate.delete(lockKey)

3.需要考虑拿到锁以后,中途有可能抛异常,从而死锁,别人再也拿不到锁
try{}catch{}finally{redisTemplate.delete(lockKey)}

4.需要考虑服务器宕机或者停电或者内存不够杀进程等等诸多物理因素,导致整个jar包停掉了,此时其他服务器上的jar包依然上正常的,可是,这样也有可能死锁
设置过期时间
redisTemplate.opsForValue().setIfAbsent(lockKey,value)
--->
redisTemplate.opsForValue().setIfAbsent(lockKey,value,10,TimeUnit.SECONDS)

5.如果过期时间过了,别人拿到锁了,但是自身没有走完所有代码,然后删除锁的时候,要确保不能删掉别人的锁
redisTemplate.delete(lockKey)
--->

value--->clientID
clientID = UUID.randomUUID().toString()
if(clientID.equals(redisTemplate.opsForValue().get(lockKey)))
{
redisTemplate.delete(lockKey)
}

6.由于判断和删掉锁是两条语句,因此,也有可能出现问题,最后的保障手段:锁续命[要新开子线程]

多jar包多redis[主从结构]

如果redis不是单台而是多台的情况,会额外新增若干问题
7.主redis挂了,A的锁丢失了[还没来得及同步给从节点],C就可以进入被锁代码
处理方案:

redlock:
与ZK的策略类似,当且仅当半数以上的redis加锁成功才会返回成功
缺陷:
半数以上的redis加锁成功了,但是还没来得及持久化,那么如果中途有断电重启什么的,就有可能出现丢锁的情况[其他请求就有可能非法加锁成功]
(可以加锁成功立马持久化,但是,这个策略还不如直接用ZK)
附录:
zookeeper与redis都可以用于分布式锁实现:
①ZK更注重一致性,因此不会出现主从不同步的问题,但是,由于会提前预防主从不同步[ZAB机制],因此,性能会比redis低
②redis更注重可用性与性能,从而有可能出现主从不同步的问题

集成的成熟工具:Redisson

posted @ 2023-06-27 11:02  356a  阅读(82)  评论(0编辑  收藏  举报