Java面试八股之Redis与MySQL双写一致性如何保证

  1. Redis与MySQL双写一致性如何保证

Redis与MySQL双写一致性问题出现在同时使用Redis作为缓存和MySQL作为持久化存储的系统中。为了在数据更新时确保Redis与MySQL的一致性,可以采用以下几种策略:

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

这是最常见的一种策略。当数据发生变更时,首先在MySQL中执行更新操作,确保数据被持久化存储。一旦数据库更新成功,立即更新Redis缓存,将新数据写入缓存。

优点:

数据完整性得到保证:由于先更新数据库,即使后续步骤失败,数据已经安全存储在MySQL中。

缓存始终反映最新数据:一旦数据库更新完成,缓存立即更新,客户端后续读取时能够获取到最新的数据。

缺点:

更新延时:在数据库更新成功与缓存更新完成之间存在时间窗口,期间如果有读请求到来,可能会读到旧数据。

数据不一致风险:在网络抖动、Redis服务器短暂不可用等情况下,可能会导致缓存更新失败,形成数据库与缓存数据的短暂不一致。

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

另一种策略是先更新Redis缓存,然后异步或同步地更新MySQL。这种策略适用于对缓存实时性要求较高的场景,可以减少读请求在更新期间看到旧数据的概率。

优点:

缩短数据更新可见时间:新数据首先写入缓存,客户端几乎立即就能读到最新数据。

减轻数据库压力:尤其是当更新操作较频繁时,先更新缓存可以避免短时间内大量写请求直接冲击数据库。

缺点:

数据丢失风险:如果在更新缓存后、更新数据库之前发生系统故障,缓存中的新数据可能丢失,且无法从数据库中找回。

一致性维护复杂:需要额外机制保证缓存更新与数据库更新的最终一致性,如使用消息队列、事务补偿等方法。

3. 两阶段提交(2PC)或分布式事务

对于需要强一致性的场景,可以采用两阶段提交(Two-Phase Commit, 2PC)或支持分布式事务的中间件来保证Redis与MySQL的原子性更新。尽管Redis本身不直接支持ACID事务,但可以通过配合其他技术(如分布式锁、消息队列等)实现类似效果。

两阶段提交流程:

准备阶段:协调者(如事务管理器)向所有参与者(Redis和MySQL)发送准备请求。参与者执行本地操作(如更新数据),但不提交,锁定资源并回复准备结果。

提交阶段:如果所有参与者均回复准备成功,协调者发送提交指令;否则,发送回滚指令。参与者根据指令提交或回滚本地事务。

优点:

强一致性:确保Redis与MySQL的数据在事务结束时保持一致。

避免中间状态:要么所有操作全部成功,要么全部回滚,避免数据处于不一致的中间状态。

缺点:

性能损耗:两阶段提交引入了额外的通信和锁定开销,可能影响系统性能。

单点故障与阻塞风险:协调者故障可能导致事务阻塞,且在某些故障情况下恢复复杂。

4. 最终一致性方案

对于可以容忍一定延迟达到一致性的场景,可以采用异步更新、消息队列、数据订阅与推送等方式实现最终一致性。

异步更新:在数据库更新后,通过后台任务或定时任务异步更新缓存。

消息队列:更新操作先写入消息队列,消费者依次更新Redis和MySQL,确保二者按序更新。

数据订阅与推送:利用MySQL的binlog订阅功能(如通过 canal 或 Debezium),每当数据库有更新时,自动将变更推送到Redis进行更新。

优点:

解耦与弹性:各组件间解耦,故障不影响整体系统运行,且能更好地应对高并发场景。

资源利用率:异步处理方式可以平滑写入负载,提高系统整体资源利用率。

缺点:

数据延迟:在最终一致达成之前,读请求可能看到旧数据。

补偿逻辑复杂:在部分更新失败时,可能需要复杂的补偿逻辑来恢复一致性。

选择哪种策略取决于具体的业务需求、对数据一致性的容忍度、系统的性能要求以及技术栈的成熟度等因素。在实际应用中,可能还需要结合使用多种策略,并辅以重试机制、超时设置、监控报警等手段来增强系统的健壮性和数据一致性保障。

 如果大家需要视频版本的讲解,欢迎关注我的B站:

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值