缓存击穿: 就是说某个访问非常频繁的热点 key ,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,直接穿过了Redis。
解决方式:
- 若缓存的数据比较固定,则可尝试将该热点数据设置为永不过期。
- 若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,则可以采用基于 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。
- 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存。
缓存穿透: 指的是缓存和数据库中都不存在的数据被请求,这种情况通常是被黑客攻击力,如果不做好防御很容易导致数据库被请求打死。比如黑客使用负数id查询你的某个表,我们的id通常不会设置为负数。
解决方式:
数据库未查询到,则在缓存中设置一个空值,这种办法无法解决采用不同负数id请求的情况。
使用布隆过滤器,将数据库中所有的数据映射到布隆过滤器中,请求打过来之前先用布隆过滤器判断是否存在,不存在直接返回就行。
缓存雪崩: 缓存雪崩发生在大量缓存同时失效的情况,会导致数据库瞬间崩溃(高并发场景),而且这种情况下如果缓存不恢复,数据库起来也没用,还是会继续被打崩。
解决方式:
- 缓存架构设计:设计高可用Redis,主从+sentinel,Redis cluster集群
- 项目服务端:使用本地缓存和服务降级处理,尽量减少请求打到MySQL
- 运维手段:定期监测Redis集群,做持久化的备份机制,一旦雪崩还能及时恢复缓存数据