redis实现分布式锁
redis的setNx和setEx实现分布式锁
原理:setNx同时只有一个能设置成功值,其他线程来改动值都不会成功,因此只有一个线程能拿到锁lock,执行完成后删除lock即可。
实现方式:
先拿分布式锁。
拿锁设置过期时间。(避免死锁)
执行业务成功,删除拿到锁。
没拿到锁,执行递归操作只到拿到锁为止。(阻塞)
存在问题:
- 问题1:第1步和第2步设置过期时间不连贯(因为redis是单线程,可能其他线程执行redis命令,例如keys * 卡死后会进行等待),不能保证原子性,因此redis提供了两条命令同时封装的函数(set key value ex 10 nx),合并为一条执行。
- 问题2:设置锁过期时间为5s,但是业务执行了10s,此时锁已删除,业务还在执行(业务时间大于锁时间),其他线程同时又能拿到锁,但是第一个线程执行完可能又会删除第二个线程的锁。
- 因此可以通过value来判断是否为自己加的锁,匹配值进行解锁(例如key产品id,value为uuid)。
- 可以给锁一直加时间,单独定时任务去处理加时间(守护线程)设置最大容忍时间。=>redisson的诞生
redisson实现分布式架构(中小公司够用)
- 配置:
- 引入相关pom依赖。(在已有redis依赖的基础上引入)
- @Bean注入相关config。
- 实现方式:
- 实现lock后能拿到锁的会一直尝试加锁,知道加锁成功为止(阻塞)(自旋锁)
- 每隔10s去检查锁是否过期,如果持有锁,则继续延长锁时间30s(避免死锁)
- 存在问题:(小概率)
- 如果redisson一直将锁写在redis主节点,然后还未同步给从节点,突然主节点挂了,redis内部会重新选举产生新的主节点。此时未同步的从节点变为了主节点,其他线程过来仍能拿到锁。
- 实现原理图
- 配置: