目录
缓存雪崩 缓存击穿-总结
缓存雪崩
出现场景:
解决方案:
缓存击穿
出现场景:
举例如图:
缓存击穿的三个前提:
解决方案:
缓存雪崩 缓存击穿-总结
缓存雪崩
出现场景:
(1) 对于Redis缓存中缓存的一些数据我们都会给它们设置一个TTL超时时间的,但是假设大量的缓存数据在同一时间这个TTL都到期了,那么大量的缓存数据都直接失效了,就会导致大量的请求打到数据库,给数据库造成巨大的压力,这样就会造成缓存雪崩。
(2) 假设说Redis缓存部署的服务器突然宕机了,那么所有的缓存在宕机的时候就直接失效了,这样同样会导致请求打到数据库,给数据库造成巨大的压力,这样也会造成缓存雪崩。
解决方案:
(1) 给Redis中缓存的不同的key的TTL有效期添加一个随机值,这样可以保证Redis缓存不会在同一时间内大量过期失效。
(2) 利用Redis集群提高服务的可用性。
分析:使用Redis集群,即使一台Redis服务器宕机了,那么其它Redis服务器也会进行一定的保证。
(3) 给缓存业务添加降级限流策略。
分析:对于缓存业务进行降级,放弃一些功能业务的优势来换取安全性。
(4)给业务添加多级缓存
分析:在一个业务中,不止是可以添加Redis缓存,我们还可以添加其它很多的缓存,比如说:JVM缓存,Nginx缓存等等。有了多级缓存,那么即使Redis缓存失效了,我们还有其它缓存进行兜底。
缓存击穿
缓存击穿问题也叫做热点Key问题,就是一个被高并发访问并且缓存重建较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
出现场景:
被高并发访问的数据被称为是热点Key数据。一个热点Key数据被缓存在Redis中,并且该热点Key数据的重建缓存的过程较为复杂,时间比较长。
那么当该热点Key突然缓存失效了。由于该热点Key数据重建缓存的时间较长,那么在这段较长的时间内,高并发的请求都会打到数据库上,这就会造成缓存击穿问题。
举例如图:
在线程1查询数据库并且重建缓存数据的过程中【该过程较长】,大量的线程请求访问该热点Key数据,都会直接打到数据库,造成缓存击穿。
缓存击穿的三个前提:
(1) 被高并发访问的数据缓存在Redis中,该缓存突然失效
(2) 该高并发访问的数据重建缓存的时间过长【因为如果重建时间过短,即使缓存失效,在访问数据库后会进行迅速的重建缓存,那么也不会造成缓存击穿的问题】
(3) 在该数据进行重建缓存的过长时间中,大量的请求过来访问该数据。
解决方案:
方案1:加互斥锁
分析流程:
添加一个互斥锁 当一个线程进行访问的时候 进行获取互斥锁,获取成功则进行作用。
如果其他线程也进入之后,获取互斥锁失败,此时会进入休眠等待,休眠等待结束后继续重试获取互斥锁,直到线程执行完查询数据库重建缓存数据并且写入缓存之后的操作之后,进行释放锁。其他线程才可以获取锁成功。
优点:
1.保证了数据的一致性,返回的一定是最新的数据。
2.实现简单,没有额外的内存消耗
缺点:
1.线程需要进行等待,性能受到很大影响。这就是化并行为串行
2.可能会有死锁风险
死锁:对于一个业务来说,我们可能会搞出多个缓存重建的操作。所以说我们加上的锁不止有一个,当我们进行获取锁的时候
可能会获取别的锁,导致别的线程获取锁失败,这种获取不到对应使用锁的情况。我们就称之为死锁!
方案2:逻辑过期
额外存储开启一个逻辑过期时间。
分析流程:
当线程1获取互斥锁成功之后,他不会在线程1内进行一系列的操作,它会额外开启一个线程2去进行操作。线程1返回过期数据即可。
当线程3进行请求数据的时候 发现获取互斥锁失败,比较佛系 直接返回过期的旧数据
当线程4开启并且正好在开启的线程2作用完毕之后进行开启的,那么会直接命中缓存 并且这个数据是最新的数据。因为是恰好在线程2操作完成之后开启作用的 !
优点:
线程无需等待,性能好
缺点:
1.不能保证数据一致性
2.因为多开启了一个逻辑时间 ,所以有额外的内存消耗
3.实现起来比较复杂
总结不易,期待三连