缓存问题
- 缓存雪崩
- 解决方案
- 缓存击穿
- 互斥锁
- 逻辑时间
- 基于互斥锁解决缓存击穿问题
- 基于逻辑过期方式解决缓存击穿问题
缓存雪崩
缓存雪崩是指在同一时间段,大量的缓存key同时失效或者Redis服务器宕机,导致大量请求到达数据库,带来巨大压力
解决方案
- 给不同的Key的TTL添加随机值
使得不容易在同一个时间段大量的缓存失效
- 利用Redis集群提高服务的可用性
如果Redis宕机了我们可以通过微服务将其他从服务器中调用及时弥补
- 给缓存业务添加降级限流策略
快要到达一个限制的时候进行降级,拒绝服务来保护缓存
- 给业务添加多级缓存
在其他层面也添加缓存,比如说nginx服务器中
缓存击穿
缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效,无数的请求访问会在瞬间给数据库带来巨大的冲击
缓存重建业务复杂:从数据库操作写入缓存操作比较复杂,耗时可能会很多
解决方案:互斥锁
,逻辑过期
互斥锁
假若有很多线程进来,访问这个被击穿的数据,这是线程1先进来,拿到互斥锁,进行后面的数据库查询,写入缓存操作,其他线程在这个期间就不会拿到互斥锁,拿不到就会进行等待过一段时间重新在缓存中进行访问
缺点:性能低,线程需要进行不断地重复等待
逻辑时间
给一些及时地数据设置逻辑时间,不设置key的TTL时间
就是假如说我有一条数据,需要在一段时间内进行高并发的访问,那我们人工给他设置一个逻辑的过期时间,可以是永不过期,在使用完成后手动的将过期时间删除
在使用逻辑数据的时候同时也用到了互斥锁,但是处理不同,在线程获得互斥锁后,再创建一个新的线程来进行写入缓存的操作,这时候先返回过期的数据,其他没有拿到互斥锁的线程也是先返回过期数据
基于互斥锁解决缓存击穿问题
在服务层中创建互斥锁方法:
private boolean tryLock(String Key){
Boolean flag = StringRedisTemplate.opsForValue().setIfAbsent(key,"1",10,TimeUnit.SECONDS);
return BooleanUtil.isTrue(flag);
}
这里是添加一个锁功能,其意思是使用setIfAbsent
方法进行插入数据,这样其他的线程就不能够再次添加数据
private void unlock(String key){
stringRedisTemplate.delete(key);
}
用来删除这个锁
基于逻辑过期方式解决缓存击穿问题
逻辑时间实例:(设置逻辑过期时间方法)
private void luoji(Long id,Long expireSeconds){
//1.查询店铺信息
Shop shop=getById(id);
//2.封装逻辑过期时间
RedisData redisdata=new RedisData();
redisdata.setdata(shop);
redisdata.setexpiretime(LocalDateTime.now().plusSeconds(expireSeconds));
//写入Redis
StringRedisTemplate.opsForValue().set(id,JSONUtil.toJsonStr(redisd ata));
}