redis缓存穿透-击穿-雪崩
缓存穿透:
查询永远绕过了缓存直接查询后台数据库,并且查询的是一个不可能存在的数据
解决方案:
当查询数据时,如果没有查询到数据,也将null返回给前端用户,同时将null数据插入缓存中,并且设置一定的过期时间。
缓存空值会有两个问题:
1、空值做了缓存,意味着缓存中存了更多的键,需要更多的内存空间;;比较有效的办法是,针对这类数据设置一个较短的过期时间,自动删除
2、缓存层和存储层的数据会有一段时间不一致,可能会对业务有一定影响,例如过期时间设定的是5分钟,如果这个时候存储添加了这条数据,那么时间就会出现缓存层和存储层的数据不一致;;这个可以利用消息系统或者其它方式清除缓存中的空对象
缓存雪崩:
大量的key设置了相同的过期时间,缓存集中在一段时间内失效,造成瞬间数据的请求数量增大,压力骤增,引起缓存雪崩
解决方案:
限流加锁排队
在缓存失效后,通过对某一个key加锁或者是队列来控制key的线程访问的数量,比如:某一个key只允许一个线程操作,比较常用的做法,是使用mutex
限流:
在缓存失效后,某一个key做count统计限流,达到一定的阈值,直接丢弃,不再 查询数据库
数据预热:
可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
做缓存降级(二级缓存)
当分布式缓存失效的时候,可以采用本地缓存,本地缓存没有再查询数据库,这种方式避免很多数据分布式缓存没有,就直接打到数据的情况
缓存击穿
是指一个key非常热点,在不停的扛着大并发,大并发集中对这个点进行访问,当这个key在失效的瞬间,持续的大并发穿破缓存,直接请求数据库
解决方案:
互斥锁
可以把key提前准备好,让缓存一直不过期
缓存与数据库数据不一致:
在并发情况下,同时操作数据与缓存会存在数据不一致的情况
解决方案:
- 对于并发几率很小的数据,这种不用考虑这个问题,很少发生缓存不一致,可以给缓存数据加上过期时间,每隔一段时间触发读的主动更新
- 就算并发很高,如果业务上能够容忍时间的缓存数据不一致,缓存加上过期时间依然可以解决大部分业务对于缓存的要求
- 如果不能容忍缓存数据不一致,可以通过加读写保证并发读写或双写的时间顺序排队,双读的时候相当于无锁
- 也可以用canal通过监听数据库的binlog日志及时的去修改缓存,只不过这里增加了系统的复杂度