• Redis缓存穿透、缓存雪崩、缓存击穿、缓存一致性、并发竞争


    缓存流程

    在讲这五个问题之前,首先我们回顾下正常的缓存的使用流程

    缓存使用流程

    程序在处理请求时,会先从缓存中进行查询,如果缓存中没有对应的key,则会从数据库中查询,如果查询到结果,并将查询结果添加到缓存中去,反之不缓存。流程就不多解释了,基于这个我们展开下面的问题。


    缓存穿透

    产生原因

    当查询一个一定不存在的key时,由于不能命中缓存,所以要查询数据库,但是这个key又不存在,所以查询不到结果,不会缓存。于是就有了利用这种一定不存在的key作为查询条件,对系统进行攻击,增加数据库压力,这种现象称为缓存穿透

    解决方法

    1. 布隆过滤
      首先要规范key的命名,对不规范的key直接过滤掉,并对所有可能的key以hash形式存储到一个足够大的bitmap中,不存在的数据会被此bitmap拦截,以避免查询数据库。
    2. 缓存空对象
      意思很简单,就是对返回数据为空的情况也进行缓存,并设置一个很短的过期时间,这样也能起缓解作用。但是这也会产生下面两个问题:
      • 缓存空对象意味着需要更多的存储空间,可再缩短缓存时间,过期自动剔除
      • 导致缓存与数据库不一致,比如某个key:a查询时还没有数据,这时会缓存空值,但是其他某个流程已走完,数据已添加到了数据库中,这时访问依旧会返回空值,因为缓存还没过期,所以解决方法就是增删改时也进行缓存的刷新

    缓存雪崩

    产生原因

    当大批量缓存集中在同一时间内失效(或者redis宕机),产生大量缓存穿透,此时又有请求并发袭来,查询压力瞬间都落在了数据库上,此时就产生了缓存雪崩

    解决方法

    1. 失效时间加随机值
      给缓存失效时间加一个随机值,避免集体失效
    2. 实现redis高可用
      通过对redis实现集群搭建来避免部分机器宕机导致redis不可用的情况
    3. 分布式锁或分布式队列
      保证缓存单线程写,并在没有获取锁的线程中一直轮询缓存,直到超时

    缓存击穿

    产生原因

    缓存击穿是指缓存中没有但是数据库中有的数据(通常是缓存到期),由于并发,未能从缓存读到数据,从而引起数据库鸭梨瞬间增大

    解决方法

    1. 设置热门缓存数据永不过期
      这里永不过期有两层意思:
      • 不设置过期时间或超长缓存时间即物理上不过期
      • 在缓存对象上添加一个标识过期时间的属性,在获取数据后校验过期时间,如果已过期则异步去更新改缓存
        这种方式可能会出现数据脏读(在缓存更新期间取到旧数据)的情况,视业务而定使用与否
    2. 分布式锁或分布式队列
      保证缓存单线程写,并在没有获取锁的线程中一直轮询缓存,直到超时

    缓存一致性

    如果对数据有强一致性要求的,那就不要使用缓存了


    缓存并发竞争

    产生原因

    多个子系统set同一个key,导致产生并发竞争

    解决方法

    1. 对key没有顺序要求
      使用分布式锁实现
    2. 对key有顺序要求
      将key对应的值带上时间戳
    3. 异步队列
      放入队列中,串行set就行
  • 相关阅读:
    Qt-不规则窗口
    Qt-绘图设备
    Qt-绘图
    许久不做前端, 偶尔看一下前端开发中的单元测试框架.
    美国6w刀的远程工作高级工程师职位,说下在线评估, 倒在第一阶段, 认知能力测试?智商不够怎么办?!
    这次说一下mysql协议的数据库中间件mycat集群方案.
    古人说, 凡事预则立, 不预则废, 设计要精确到每个细节.
    探索产品经理之路.
    今天我们看一下caloch.cn的邮件问题
    We go for our interest in drawing manga characters.
  • 原文地址:https://www.cnblogs.com/wandoupeas/p/redis_problems.html
Copyright © 2020-2023  润新知