缓存问题

缓存穿透

假设某个数据redis不存在,mysql也不存在,而且一直尝试读怎么办?缓存穿透,数据最终压力依然堆积在mysql,可能造成mysql不堪重负而崩溃;

解决

  1. 发现mysql不存在,将redis设置为 <key, nil> 设置过期时间 下次访问key的时候 不再访问mysql 容易造成redis缓存很多无效数据;
  2. 布隆过滤器,将mysql当中已经存在的key,写入布隆过滤器,不存在的直接pass掉;
  3. 使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。

缓存击穿

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

原理图

解决

  1. 加锁
    (1)就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db。

    (2)先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key

    (3) 当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;

    (4) 当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。

  2. 将很热的key,设置不过期

  3. 在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长

  4. 现场监控哪些数据热门,实时调整key的过期时长

缓存雪崩

表示一段时间内,缓存集中失效(redis无 mysql 有),导致请求全部走mysql,有可能搞垮数据库,使整个服务失效;

解决

缓存数据库在整个系统不是必须的,也就是缓存宕机不会影响整个系统提供服务;

  1. 如果因为缓存数据库宕机,造成所有数据涌向mysql:

    采用高可用的集群方案,如哨兵模式、cluster模式;

  2. 如果因为设置了相同的过期时间,造成缓存集中失效:

    设置随机过期值或者其他机制错开失效时间;

  3. 如果因为系统重启的时候,造成缓存数据消失:

    重启时间短,redis开启持久化(过期信息也会持久化)就行了; 重启时间长提前将热数据导入redis当中;

posted @ 2022-06-21 22:44  DarkH  阅读(27)  评论(0编辑  收藏  举报