目录
概要
问题:我看你做的项目中,都用到了Redis, 你在最近的项目中哪些场景使用了redis呢?
一般回答:
缓存 缓存三兄弟(穿透、击穿、雪崩)、双写一致、持久化、数据过期策略、数据淘汰策略
分布式锁 setnx、redisson
消息队列、延迟队列 何种数据类型
这一章节我简单描述一下Redis分布式锁的回答,写的可能不太好,大家仅供参考,谢谢。
分布式锁
Redis实现分布式锁主要利用Redis的setnx命令。setnx是 SET if not exists (如果不存在,则SET)的简写
#添加锁,NX是互斥、EX是设置超时时间
SET lock value NX EX 10
#释放锁,删除即可
DEL key
Redis分布式锁如何合理的控制锁的有效时长?
redisson实现的分布式锁-执行流程
采用看门狗的策略,来给锁续期,达到锁持有合理的有效时长。代码如下
public void redisLock() throws InterruptedException {
//获取锁(重入锁),执行锁的名称
RLock lock = redissonClient.getLock( s: "ceshilock");
//尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
//boolean isLock = lock.tryLock(10,30, TimeUnit.SECONDS);
boolean isLock =LockAtryLock(time: 10, TimeUnit.SECONDS);
//判断是否获取成功
if (isLock) {
try {
System.out.println("执行业务");
} finally {
//释放锁
Lock.unLock();
}
}
}
redisson实现的分布式锁-可重入
采用了hash结构记录线程ID和重入次数,hash结构如下:
以下代码表示锁的可重入的例子:
public void add1(){
//注意锁的名字相同
RLock lock =redissonClient.getLock(“ceshilock");
boolean isLock = lock.tryLock();
//执行业务
add2();
//释放锁
lock.unlock();
}
public void add2(){
//注意锁的名字相同
RLock lock =redissonClient.getLock("ceshilock");
boolean isLock = lock.tryLock();
//执行业务
//释放锁
lock.unlock();
}
redisson实现的分布式锁-主从一致性
RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁(n/2+1),避免在一个redis实例上加锁,(不建议采用)
总结
面试官:Redis分布式锁如何实现?
候选人:嗯,在redis中提供了一个命令setnx(SET if not exists)
由于redis的单线程的,用了命令之后,只能有一个客户端对某一个key设置值,在没有过期或删除key的时候是其他客户端是不能设置这个key的
面试官:好的,那你如何控制Redis实现分布式锁有效时长呢?
候选人:嗯,的确,redis的setnx指令不好控制这个问题,我们当时采用的redis的一个框架redisson实现的。
在redisson中需要手动加锁,并且可以控制锁的失效时间和等待时间,当锁住的一个业务还没有执行完成的时候,在redisson中引入了一个看门狗机制,就是说每隔一段时间就检查当前业务是否还持有锁,如果持有就增加加锁的持有时间,当业务执行完成之后需要使用释放锁就可以了
还有一个好处就是,在高并发下,一个业务有可能会执行很快,先客户1持有锁的时候,客户2来了以后并不会马上拒绝,它会自选不断尝试获取锁,如果客户1释放之后,客户2就可以马上持有锁,性能也得到了提升。
面试官:好的,redisson实现的分布式锁是可重入的吗?
候选人:嗯,是可以重入的。这样做是为了避免死锁的产生。这个重入其实在内部就是判断是否是当前线程持有的锁,如果是当前线程持有的锁就会计数,如果释放锁就会在计算上减一。在存储数据的时候采用的hash结构,大key可以按照自己的业务进行定制,其中小key是当前线程的唯一标识,value是当前线程重入的次数
Redisson锁能解决主从数据一致的问题吗
不能解决,但是可以使用redisson提供的红锁来解决,但是这样的话,性能就太低了,如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁