Skip to content

缓存异常

缓存一致性问题

只要是缓存都会存在这种问题,数据库与缓存之间同步的问题,这里主要有四种情况,每种情况会具体分析其存在的问题,可以根据业务情况选择使用。

  1. 先更新数据库,后更新缓存

    问题: 在并发访问的情况下,会将脏数据刷新到缓存中。(应该没人使用)

  2. 先更新缓存,后更新数据库

    问题: 如果更新缓存成功,但是数据库更新失败则会导致数据不一致问题。(应该没人使用)

  3. 先删除缓存,后更新数据库

    改方案也会出现问题,此时来个两个请求,请求A 更新操作;请求B 查询操作。

    • 请求A进行写操作,删除缓存
    • 请求B查询操作发现缓存不存在
    • 请求B去数据库可查询得到旧值
    • 请求B将旧值写入到缓存
    • 请求A将新值写入数据库

    删除情况导致不一值的问题出现,如果不采用给缓存设置过期策略,那么改缓存中永远都是脏数据。

    解决方案:

    • 延迟双删除: 在更新数据库后间隔1s再次删除缓存,那么可以将1s内的脏数据清除。
  4. 先更新数据库,后删除缓存

    这种情况下,如果更新数据库成功了,但是在删除缓存阶段出错没有删除成功,那么此时在读取缓存的时候每次都是错误的数据。

    解决方式:

    • 删除补偿:针对删除Redis删除失败的情况,将key作为消息发送到消息队列中,进行删除补偿。

缓存雪崩

概念:

 指缓存中大量的数据失效,导致大量请求直接访问数据库,造成数据库压力过大。通常是由于缓存中大量的数据在同一时间失效,导致大量请求直接访问数据库。

解决方式:

  • 可以采用多级缓存架构,减少缓存层的压力
  • 或者设置热点数据的过期时间为随机时间,避免在同一时间大量数据同时失效(常用方式
  • 另外可以在缓存层和数据库层之间添加限流、熔断等措施
  • 避免因突发流量导致系统崩溃

缓存击穿

概念:

 指缓存中某个热点数据失效,此时有大量并发请求同时访问这个失效的数据,导致这些请求直接访问数据库,造成数据库压力过大,甚至导致数据库崩溃。

 通常是由于缓存中某个热点数据过期失效,同时有大量并发请求访问该数据。

解决方式:

  • 可以使用锁机制或者分布式锁机制,避免大量并发请求同时访问失效的热点数据
  • 或者不设置TTL,设置逻辑上过期标识,需要过期的时候直接删除标识

缓存穿透

概念:

 指查询一个不存在的数据,由于缓存中没有数据,所以这个查询请求会直接穿过缓存层,到达数据库层,造成了数据库的压力。

 攻击者可以通过构造恶意请求,使得缓存层无法命中任何数据,从而导致请求直接访问数据库,从而引起数据库压力过大。

解决方式:

  • 可以在查询缓存之前,先对请求的参数进行合法性检查,如过滤非法字符、判断参数范围等
  • 或者使用BloomFilter等数据结构,对查询参数进行过滤,只有在BloomFilter中判断有可能存在的情况下才会去查询数据库。