Redis_缓存3_缓存异常(数据不一致、雪崩、击穿、穿透)

14.6缓存异常

四个方面

  • 缓存中数据和数据库不一致
  • 缓存雪崩
  • 缓存击穿
  • 缓存穿透

14.6.1数据不一致:

一致性包括两种情况

  • 缓存中有数据,需要和数据库值相同
  • 缓存中没有数据,数据库中的数据是最新值

如果不符合以上两种情况,则出现数据不一致的问题。

读写缓存

  • 同步直写
  • 异步写回

只读缓存

  1. 新增数据
    • 数据直接写到数据库中,缓存不做操作。满足一致性两种情况的第2种。
  2. 删改数据
    • 先删除缓存,后更新数据库。可能会导致,缓存删除成功,数据库更新失败。业务逻辑去访问数据时,缓存中查不到数据,缓存缺失,到数据库中查询,所以只拿到旧的数据。
    • 如果新更新数据库,再删除缓存。可能会导致,数据库更新成功,缓存删除失败。数据库中的数据是新的值,缓存中存储的是旧值。再读取时,先从缓存中读取,读取到了旧值。

解决数据不一致的方案

  • 重试机制:把删除的缓存值或要更新数据库值先存储到消息队列中(kafka消息队列)。
  • 如果发现试了10次还不成功就会向服务器端报错

多线程访问的情况

  1. 先删除缓存,再更新数据库。

    • 假设T1线程先删除缓存,再执行更新数据库。还未更新成功时,T2线程进行读取,发现缓存中没有数据,到数据库中读取,会读取到旧的数据。如果T2还将旧数据更新到缓存中,那T1线程再进行读取,也读到的旧值。

    • 让T1线程先执行休眠一段时间。T1线程在休眠时间,让T2线程执行结束,会将数据重新写入缓存。T1线程再做一次缓存删除操作。"延迟双删 "。

      java 复制代码
      redis.delCache()
      db.update()
      Thread.sleep(2000)
      redis.delCache()
  2. 先更新数据库值,再去删除缓存

    • 假设T1线程先删除或更新数据库中的值,还没来得及删除缓存时,T2线程就开始读取数据。T2会先从缓存中读取,缓存命中,T2拿到的就是旧的数据。直到T1将缓存中数据删除,其他线程再次读取,可以拿到新值.
并发操作 执行顺序 可能出现问题 问题描述 解决方案
没有 先删除缓存,后更新数据库 缓存删除成功,数据库更新失败 从数据库读到旧数据 重试(通过消息队列)
先删除缓存,后更新数据库 缓存删除,未更新数据库,其他线程并发访问 并发线程从数据库读到旧值,并更新了缓存,其他线程都从缓存中读到旧值 延迟双删
没有 先更新数据库,后删除缓存 数据库更新成功,缓存删除失败 从缓存中读到旧值 重试(通过消息队列)
先更新数据库,后删除缓存 数据库更新成功,未删除缓存,其他同线程并发访问 并发线程从缓存读到旧值 会有数据不一致情况短暂存在

14.6.2 缓存雪崩

大量的应用请求无法在redis中完成处理。缓存中读取不到数据,直接进入到数据库服务器。数据库压力激增,数据库崩溃,请求堆积在redis,导致redis服务器崩溃,导致redis集群崩溃,应用服务器崩溃,称为雪崩

原因1:缓存中有大量数据同时过期

解决方案:

  1. 页面静态化处理数据:对于不经常更换的数据,生成静态页
  2. 避免大量数据同时过期:为商品过期时间追加一个随机数,在一个较小的范围内(1~3分钟)。
  3. 构建多级缓存架构:redis缓存+nginx缓存+ehcache缓存
  4. 延长或取消热度超高的数据过期时间
  5. 服务降级

不同的数据采取不同的处理方式。

原因2:redis实例故障

解决方案:

  1. 服务熔断或限流处理

提前预防:

  • 灾难预警:监控redis服务器性能指标,包括数据库服务器性能指标,CPU、内存、平均响应时间、线程数等
  • 集群:有节点出一故障,主从切换。

14.6.2 缓存击穿

对某个访问频繁热点数据的请求。主要发生在热点数据失效

解决方案:

  • 预先设定:电商双11,商铺设定几款是主打商品,延长过期时间
  • 实时监控:监控访问量,避免访问量激增
  • 定时任务:启动任务调度器,后台刷新数据有效期
  • 分布式锁:可防止缓存击穿,但会有性能问题 (不推荐)

14.6.3 缓存穿透

要访问的数据在redis中不存在,在数据库中也不存在。

原因:

  1. 业务层误操作
  2. 恶意攻击

解决方案:

  1. 缓存空值或缺省值
  2. 使用布隆过滤器,快速判断数据是否存在
  3. 在请求入口前端进行请求检测
  4. 实时监控
  5. key加密
相关推荐
盖世英雄酱581363 分钟前
定时任务框架原理剖析、对比、选型
java·后端
局外人LZ19 分钟前
DM8数据库Docker镜像部署最佳实践
数据库·docker·容器·达梦
lixn43 分钟前
读懂Java字节码(1)
jvm·后端
亲爱的非洲野猪1 小时前
如何优雅解决缓存与数据库的数据一致性问题?
java·分布式·缓存·kafka·lock
JeffreyGu.1 小时前
【Oracle】Oracle 11g打补丁时遇到opatch apply命令无法识别
数据库·oracle
小李同学_LHY1 小时前
第一章: 初识 Redis:背后的特性和典型应用场景
数据库·redis·缓存
七夜zippoe1 小时前
PostgreSQL 终端命令详解及实际应用案例
数据库·postgresql·oracle
百度Geek说1 小时前
首发!百度百科全系能力上线千帆,权威知识增强Agent一键打造
后端
瑾曦2 小时前
Maven高级
后端
bobz9652 小时前
操作系统驱动崩溃为什么会导致系统卡顿?
后端