面试官,如何保证缓存与数据库的数据一致性

简介: 面试官,如何保证缓存与数据库的数据一致性

0. 缓存更新策略


内存淘汰 超时剔除 主动更新
说明 利用redis的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存 给缓存数据添加过期时间,到期后删除缓存,下次查询再更新缓存 编写业务逻辑,自己控制在修改数据库时更新缓存
一致性 一般
维护成本


0.1 缓存主动更新策略


  • 方案一:由缓存的调用者在更新数据库的时候同时更新缓存
  • 方案二:将缓存和数据库整合为一个服务,由该服务来维护一致性。对外提供接口,调用者调用该服务提供的接口,无需关心缓存一致性问题
  • 方案三:调用者只操作缓存,由其他线程异步将缓存数据持久化到数据库,保证最终一致性。


1. 数据同步策略


1.1 设置有效期


  • 给缓存设置有效期
  • 优点:简单方便
  • 缺点:时效性差,缓存过期之前可能数据不一致
  • 场景:适合更新频率低,时效性要求低的业务


1.2 同步双写


  • 在修改数据库的同时,直接修改缓存
  • 优点:时效性强,缓存与数据库强一致
  • 缺点:有代码侵入,耦合度高
  • 场景:对一致性、时效性要求较高的缓存数据


1.3 异步通知


  • 修改数据库时发送事件通知,相关服务监听到通知后再修改缓存数据
  • 优点:低耦合,可以同时通知多个缓存服务
  • 缺点:时效性一般,可能存在中间不一致状态
  • 场景:时效性要求一般,有多个服务需要同步


2. 保证缓存与数据库一致性的四个方案


  • 先更新数据库,再更新缓存(有bug)
  • 并发更新数据库场景下,会将脏数据刷新到缓存,不推荐
  • 先更新缓存,再更新数据库(有bug)
  • 缓存更新成功后,数据库更新失败,则会造成数据不一致性,而且也有并发问题,不推荐
  • 先删除缓存,在更新数据库(有bug)

* 改进方法:先删缓存,再更新数据库,再删缓存

  • 先更新数据库,再删除缓存(有bug)

* 更新数据库成功,但是删除缓存失败。

* 推荐这种,更新完数据库后删除缓存的速度是非常快的,所以在这个间隔内插入其他事务概率会比较低。


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


3.1 可能出现的问题


  1. 请求A进行写操作,删除缓存
  2. 请求B查询发现缓存不存在
  3. 请求B去数据库查询得到旧值
  4. 请求B将旧值写入缓存
  5. 请求A将新值写入数据库


如果没有给缓存设置过期时间,则缓存数据永远都是脏数据


3.1 解决方式:延时双删


  • 先淘汰缓存
  • 再写数据库
  • 休眠一秒后再次淘汰缓存


对于读写分离的数据库,主从同步之间也会有时间差,若此时来了两个请求,请求A(更新操作)和请求B(查询操作),也会出现一些问题


  1. 请求A更新操作,删除缓存
  2. 请求A再主库进行更新操作,主库与从库进行数据同步操作
  3. 请求B查询操作,发现redis中没有数据
  4. 请求B去从库获取旧值数据
  5. 请求B更新缓存
  6. 主从同步完成


50df51aec22c426a5d58d808ecfde60b_format,png.png

解决方法:如果对redis进行填充的查询数据库操作,那么强制将其指向主库进行查询

d294efc41e46ea61ec930b578183261e_format,png.png


4. 先更新数据库,后删除缓存(推荐)


4.1可能出现的问题


  • 更新数据库成功了,但是在删除缓存的阶段没有成功,则之后读取的缓存都是错误的


4.2解决方式一:异步实现之利用消息队列


  1. 请求A向服务端发送修改商品请求
  2. 相应的模块根据请求会对数据库对应内容进行更新,更新成功后会向MQ发送消息

1. 该消息通知缓存处理模块删除对应的缓存

  1. 缓存模块监听到有新的消息,会执行缓存删除逻辑

1. 利用消息队列的 手动提交机制 可以保证删除逻辑顺利完成




4.3 解决方式二:基于Canal的通知


  • 商品服务完成数据库修改操作后,业务直接结束。没有任何代码侵入
  • Canal监听mysql变化,当发现变化后,立即通知缓存服务
  • 缓存服务接收到canal通知,删除缓存。




相关文章
|
8月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1500 5
|
缓存 NoSQL 关系型数据库
WordPress数据库查询缓存插件
这款插件通过将MySQL查询结果缓存至文件、Redis或Memcached,加速页面加载。它专为未登录用户优化,支持跨页面缓存,不影响其他功能,且可与其他缓存插件兼容。相比传统页面缓存,它仅缓存数据库查询结果,保留动态功能如阅读量更新。提供三种缓存方式选择,有效提升网站性能。
304 1
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
存储 缓存 NoSQL
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
444 1
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
415 4
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
2522 2
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。