Redisson
基于setnx实现的分布式锁存在下面的问题:
1)不可重入
同一个线程无法多次获取同一把锁
2)不可重试
获取锁只尝试一次就返回false,没有重试机制
3)超时释放
锁超时释放虽然可以避免死锁,但如果是业务执行耗时较长,也会导致锁释放,存在安全隐患
4)主从一致性
如果redis提供了主从集群,主从同步存在延迟,当主宕机时,如果从同并步主的数据锁,则会出现锁实现
Redisson是什么?
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(Iln-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现
Redisson入门
1.引入依赖:
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
2.配置Redisson客户端:
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
//配置类
Config config = new Config();
//添加redis地址,这里添加了单节点地址,可以使用config.useClusterServers()添加集群地址。
config.useSingleServer().setAddress("redis://192.168.56.10:6379").setPassword("1314520wang");
//创建客户端
return Redisson.create(config);
}
}
3.使用Redisson的分布式锁:
RLock lock = redissonClient.getLock("lock:order:" + user.getId());
//获取锁
boolean isLock = lock.tryLock();
//判断是否获取锁成功
if(!isLock){
//获取锁失败,返回错误或者重试
return Result.fail("不允许重复下单");
}
try {
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.createVoucherOrder(voucherId);
} finally {
lock.unlock();
}
Redisson可以重入锁的原理
核心:
利用hash结构,去记录获取锁的线程以及重入的次数。
流程
Redis的分布式锁原理
1)可重入:可重入:利用hash结构记录线程id和重入次数
2)可重试:利用信号量和PubSub功能实现等待、唤醒,获取
锁失败的重试机制
3)超时续约∶利用watchDog,每隔一段时间( release Time / 3)重置超时时间
整体流程
总结:
1)不可重入Redis分布式锁:
原理:利用setnx的互斥性;利用ex避免死锁;释放锁时判断线程标示
缺陷:不可重入、无法重试、锁超时失效
2)可重入的Redis分布式锁:
原理:利用hash结构,记录线程标示和重入次数;利用watchDog延续锁时间;利用信号量控制锁重试等待缺陷:redis宕机引起锁失效问题
3) Redisson的multiLock:
原理:多个独立的Redis节点,必须在所有节点都获取重入锁,才算获取锁成功
缺陷:运维成本高、实现复杂