缓存问题
缓存穿透
假设某个数据redis不存在,mysql也不存在,而且一直尝试读怎么办?缓存穿透,数据最终压力依然堆积在mysql,可能造成mysql不堪重负而崩溃;
解决
- 发现mysql不存在,将redis设置为 <key, nil> 设置过期时间 下次访问key的时候 不再访问mysql 容易造成redis缓存很多无效数据;
- 布隆过滤器,将mysql当中已经存在的key,写入布隆过滤器,不存在的直接pass掉;
- 使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
缓存击穿
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
原理图
解决
加锁
(1)就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db。(2)先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key
(3) 当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;
(4) 当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。
将很热的key,设置不过期
在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
现场监控哪些数据热门,实时调整key的过期时长
缓存雪崩
表示一段时间内,缓存集中失效(redis无 mysql 有),导致请求全部走mysql,有可能搞垮数据库,使整个服务失效;
解决
缓存数据库在整个系统不是必须的,也就是缓存宕机不会影响整个系统提供服务;
如果因为缓存数据库宕机,造成所有数据涌向mysql:
采用高可用的集群方案,如哨兵模式、cluster模式;
如果因为设置了相同的过期时间,造成缓存集中失效:
设置随机过期值或者其他机制错开失效时间;
如果因为系统重启的时候,造成缓存数据消失:
重启时间短,redis开启持久化(过期信息也会持久化)就行了; 重启时间长提前将热数据导入redis当中;