1.redis的解决分布式锁的bug
Redis分布式锁不能解决超时问题,分布式锁有一个超时时间,程序的执行如果超出了锁的超时时间就会出现问题。
可以使用:redission依赖,redission解决redis超时问题的原理。
为持有锁的线程开启一个人守护线程,守护线程会每隔10秒检查当前线程是否持有锁,如果持有则延迟生存时间。
使用:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
//获取redisson对象并交于spring容器管理
@Bean
public Redisson redisson(){
Config config =new Config();
config.useSingleServer().
setAddress("redis://localhost:6379").
//redis默认有16个数据库
setDatabase(0);
return (Redisson) Redisson.create(config);
}
@Override
public String decreaseStock(Integer productId) {
//获取锁对象
RLock lock = redisson.getLock("aaa::" + productId);
try {
lock.lock(30, TimeUnit.SECONDS);
//查看该商品的库存数量
Integer stock = productStockDao.findStockByProductId(productId);
if (stock > 0) {
//修改库存每次-1
productStockDao.updateStockByProductId(productId);
System.out.println("扣减成功!剩余库存数:" + (stock - 1));
return "success";
} else {
System.out.println("扣减失败!库存不足!");
return "fail";
}
} finally {
lock.unlock();
}
}
2. redis面试题
redis中常见的面试题
2.1 什么是缓存穿透?怎么解决?
1. 数据库中没有该记录,缓存中也没有该记录,这时候有人恶意的大量访问这样的数据。这样就会导致请求绕过缓存,直接访问数据,从而造成数据库压力过大。
2.解决方法:
【1】在controller加数据校验。
【2】我们可以在redis中存入一个空对象,返回值为空,只不过这个对象的过期时间不能太长,最多不超过5分钟。
【3】使用布隆过滤器。底层:有一个bitmap数组,里面存储了该表的所有id。
//伪代码
String get(String key) { //布隆过滤器钟存储的是数据库表钟对应的id
String value = redis.get(key); //先从缓存获取。
if (value == null) { //缓存没有命中
if(!bloomfilter.mightContain(key)){//查看布隆过滤器钟是否存在
return null;
}else{
value = db.get(key); //查询数据库
redis.set(key, value);
}
}
return value;
}
2.2 什么是缓存雪崩?如何解决?
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至造成down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据过期了,很多数据都查不到需要从数据库查询。
1.什么情况下会发生缓存雪崩
【1】项目刚上线,缓存中没有任何数据。
【2】缓存出现大量过期时间
【3】redis宕机
2.解决方法:
【1】上线前先把一些热点数据放入缓存。
【2】设置过期时间为散列值。
【3】搭建redis集群
2.3 什么是缓存击穿?如何解决?
缓存击穿是指缓存中没有但数据库中有数据(一般是缓存时间到),这是由于并发用户特别多,同时读缓存没有读到数据,又同时去数据库中取数据,引起数据库压力瞬间增大,造成过大压力。
缓存击穿解决方案:
【1】设置永久不过期。【这种适合内存】
【2】使用互斥锁(muten key)业界比较常用的做法。