分布式锁
- 基于Redis
1.可以使用Redisson实现分布式锁;
@SpringBootTest
class DemoApplicationTests {
@Resource
private Redisson redisson;
@Resource
private RedisTemplate redisTemplate;
@Test
public void deductStock() {
//获取锁
String lockKey = "lockKey";
RLock lock = redisson.getLock(lockKey);
lock.lock();
//业务代码
try{
int stock = Integer.parseInt((String) redisTemplate.opsForValue().get("stock"));
redisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);
if(stock > 0){
redisTemplate.opsForValue().set("stock",(stock-1)+"");
System.out.println("扣减成功,库存stock:"+(stock - 1) + "");
}else{
System.out.println("扣减失败,库存不足");
}
}finally {
//一定要在finally块中释放锁
lock.unlock();
}
}
}
Redisson原理如下,帮助理解:
会出现的问题:lock刚发送到master节点,还未同步到slave节点时,master节点挂掉。slave节点变为master节点,此时会导致线程可以获取到锁,但时线程仍然持有锁且正在执行业务逻辑代码。解决方案:使用zk分布式锁
- 基于Zookeeper
zk为什么能够解决上述出现的问题:zk的分布式集群机制和选举机制天生支持所丢失问题。watch回调机制可以优化Redisson的自旋问题。
zk集群中,leader会先讲信息同步到follwer节点存储到log中,然后给leader节点发送ack,当leader收到半数以上的ack时,才会返回给客户端数据创建成功。如果leader节点挂了,zk集群会选出信最多的follwer节点作为leader节点,保证不会造成所丢失问题。