缓存穿透
引发原因
对不存在的资源的大量访问:web
服务器接收到大量对“不存在的资源”的访问请求(一般是黑客故意访问不存在的资源),由于资源压根不存在,所以redis
中也没有相应的缓存,那么web
服务器就会去访问mysql
,对 mysql 的大量访问,就会造成数据库崩溃。
解决方案
-
对空值缓存:当对某个
key
的请求不在redis
中,也不在mysql
中,此时对这个key
设置一个value
为null
的缓存,并把这个key
过期时间设短点,这样,下次再有对这个key
的访问,就不用去查询mysql
了。 -
设置可访问的名单(白名单):利用
bitmaps
或者 布隆过滤器,对mysql
中可以访问的资源作记录,只有当要求访问的资源存在,但是不在缓存中,才会去访问mysql
。 -
进行实时监控,设置黑名单:当发现
Redis
的命中率开始急速降低,需要排查访问对象和访问的数据,对于大量访问不存在资源的用户,对其设置黑名单。
缓存击穿
引发原因
某个热点 key 过期:key对应的数据存在,但在redis
中刚好过期,此时这个 key
如果突然变成热点 key,出现大量对其的访问请求,这些请求发现缓存过期一般都会从后端DB
加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB
压垮。
解决方案
-
预先设置热门数据:在
redis
高峰访问之前,把一些热门数据提前存入到redis
里面,加大这些热门数据key
的时长(例如,在情人节到来前,将花、口红商品设为热点数据) -
实时调整:现场监控哪些数据热门,实时调整
key
的过期时长 -
使用锁:既然是由于对DB的大量同时请求导致的,那么对这个
key
加上锁,使他们对DB的请求不再是同时的,缓解DB的压力。
助记:
一般是由娱乐明星的突发新闻引起,“击”?“鸡你太美”?(咳咳,实在没法从名字区分开穿透和击穿。。。)
缓存雪崩
引发原因
短时间内,大量 key 过期:缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key,就行“雪崩”一样。
解决方案
- 将缓存失效时间分散开:在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
- 设置过期标志更新缓存(提前通知):设置提前量,如果过期会触发通知另外的线程在后台去更新实际key的缓存。
-
构建多级缓存架构:
nginx
缓存 +redis
缓存 +其他缓存(ehcache
等) - 使用锁或队列:用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。但是不适用高并发情况。
参考:
尚硅谷视频