缓存三兄弟
缓存穿透
查询一个不存在的数据,redis查询不到,再查询mysql也查询不到,也不会直接写入缓存,导致每次请求都查询数据库
有人恶意通过发送大量不存在的请求,导致数据库宕机
解决方案一:缓存
redis缓存空数据,查询返回的数据为空,仍然把这个空结果进行缓存
优点:简单
缺点:消耗内存,可能会发生不一致的问题
解决方案二:布隆过滤器
布隆过滤器,在查询redis前,先查询布隆过滤器,检索一个元素是否在一个集合中
布隆过滤器原理:
存储数据:通过对数据进行若干个哈希函数计算得到哈希值,将bitmap对应位置的值置为一
查询数据:使用相同的哈希函数获取哈希值,判断对应位置是否都为一,如果不全为一说明不存在
注意:“不存在一定不存在,存在不一定存在”
误判率:作为一个参数可以被设置,数组越小误判率越大,数组越大误判率越小,但响应的内存占用越大
优点:占用内存少,没有多余key
缺点:实现复杂,存在误判
缓存击穿
给某一个热点key设置了过期时间,当key过期时,恰好这时这个时间点对这个key有大量的并发请求,可能导致压垮数据库
解决方案一:互斥锁
互斥锁,当线程查询redis失败后,不立刻去请求数据库,而是使用如Redis的setnx去设置一个互斥锁,当获取锁成功时才进行查询,写入缓存完成后在释放锁
优点:可以保证redis和数据库的强一致性
缺点,性能差
解决方案二:自动续期
缓存击穿是由于热点key过期导致的,所以可以使用一个job给热点key自动更新缓冲,重新设置过期时间为30分钟
解决方案三:永不过期
对于很多热门key,其实是可以不用设置过期时间,让其永久有效的。比如参与秒杀活动的热门商品,由于这类商品id并不多,在缓存中我们可以不设置过期时间。在秒杀活动开始前,我们先用一个程序提前从数据库中查询出商品的数据,然后同步到缓存中,提前做预热
等压力过去之后,再手动删除这些无用的缓存
缓存雪崩
同时有多个key失效或者redis服务宕机,导致大量请求到达数据库,给数据库带来巨大压力
解决方案一:过期时间加随机数
为了解决缓存雪崩问题,我们首先要尽量避免缓存同时失效的情况发生,可以在过期时间上加上一个随机数,这样即使在高并发的情况下,多个请求同时设置过期时间,由于有随机数的存在,也不会出现太多相同的过期key。
解决方案二:高可用
针对缓存服务器down机的情况,在前期做系统设计时,可以做一些高可用架构。比如:如果使用了redis,可以使用哨兵模式,或者集群模式,避免出现单节点故障导致整个redis服务不可用的情况。
使用哨兵模式之后,当某个master服务下线时,自动将该master下的某个slave服务升级为master服务,替代已下线的master服务继续处理请求。