缓存与数据库一致性终极指南:从入门到放弃?不,到精通!下

简介: 本文探讨缓存一致性难题,从延时双删到重试机制,分析同步重试、异步重试、消息队列补偿及Binlog监听(Canal)等方案,结合优缺点与适用场景,最终提出根据业务需求权衡一致性与性能,选择合适策略。

上篇文章提到了延时双删仍然会存在删除缓存失败的情况。需要通过重试机制来保障删除缓存的成功率


前情回顾

上回说的小树做了一个缓存的功能,可是出现了数据不一致的情况,经过老大哥的指教,先是想到了旁路缓存的思路,后面还是会存在数据不一致的问题,经过几番优化,又找到了延时双删的策略来减少并发时出现的问题。可是仍然没有解决删除缓存时可能失败的问题,只是提到了可以考虑使用失败重试机制

失败重试的方案

老大哥跟小树说:
失败重试的方法一般分为两类

  • 同步重试
  • 异步重试

同步重试的实现就很简单了,直接在程序中实现,失败后再次删除,达到一定次数后停止重试。缺点也很明显,并发高的时候对接口性能很大。
异步的实现方式就很多了:

  1. 通过线程实现
    每次新增一个线程来进行重试操作。高并发下容易创建太多线程,会出现OOM问题;
    当然你可以通过线程池来管理线程,这样可以避免OOM问题
    但通过线程来进行重试的话,无法保留重试的记录,如果服务器重启,尚未重试成功的数据就会丢失
  2. 重试内容写入表中,通过定时任务执行
  3. 将重试的内容写入消息中间件中,通过消费消息来删除缓存,由消息中间件来保证消息的可靠消费

小树听了上面的三种方式说:第一种和第二种方法太简单了。你还是给我讲讲消息队列的方法吧

消息队列补偿

通过异步解耦,确保缓存删除操作最终成功。

实现步骤

322f7e932e60d4eabf45eb0cda1da5dd_MD5.jpeg

  1. 用户操作数据后,程序先更新数据库,然后删除缓存,成功直接返回,失败则放入消息中间件中
  2. 消费者检测到有消息开始消息消息,执行删除缓存操作,成功后删除这条消息,失败则进行重试,重试达到一定次数后,可根据业务做出处理如写入表中或者直接抛出错误

    优缺点

优点 缺点 适用场景
高可靠性 系统复杂度高 分布式系统
解耦业务 消息可能堆积 订单/支付系统

选型建议

  • 低并发场景:用Redis Stream实现轻量级队列
  • 高并发场景:RocketMQ + 死信队列监控

小树听了上面几种方案,又提问道:如果选上面几种方案的话,我需要改造原来的代码逻辑,有没有不需要改动原来代码就可以完成删除缓存的操作

方案四:Binlog监听(Canal)

通过数据库日志驱动缓存更新,实现业务零侵入。

Canal部署架构

27d8115546fc8f9d3e803fc0cfb7ac58_MD5.jpeg

具体方案如下:

  1. 程序只需要更新数据库就好了,其他的操作完全不关心。
  2. 中间件会伪装为MySQL 的从库,同步订阅binlog日志来获取变更的数据。
  3. binlog订阅者获取变更的数据,然后删除缓存。

优势

  • 完全解耦业务代码
  • 实时性达到毫秒级

    优缺点

优点 缺点 适用场景
业务零侵入 部署复杂 微服务架构
毫秒级同步 需处理DDL事件 数据异构同步

适用场景

  • 微服务架构中多个服务共享缓存
  • 数据异构场景(如ES索引同步)

小树听了总结道:上面这些方案我都理解了,但这些方案好像都只是尽量避免缓存不一致的情况,并没有真正的实现读缓存的时候一定和数据库保持一致
老大哥点了点头,说:是的,数据库追求数据的准确性和持久性,而缓存则追求极致的响应速度。大部分应用缓存的场景都是可以允许短暂的数据不一致的情况的,也就是最终一致性。如果追求强一致性,不可避免的就要牺牲一部分的响应性能。

常见的方案就是加锁,加锁方式又分为乐观锁和悲伤锁两种,这两个概念之前的文章有介绍过,这里简单总结一下各自的特点,就不详细介绍了

乐观锁:版本号控制

通过数据版本校验,实现精准更新。

额外成本

  • 存储开销增加5%-10%
  • 所有读写操作需校验版本号

回报

  • 缓存命中率提升40%
  • 彻底解决并发更新导致的脏读

终极大招:分布式锁

通过互斥锁确保同一时刻只有一个写操作。

性能数据

  • 吞吐量下降60%(实测)
  • 平均响应时间从20ms → 80ms

使用铁律

  • 仅用于库存扣减等核心场景
  • 必须设置锁超时时间!

最后抉择:一表帮你选型

场景特征 推荐方案 一致性强度 性能影响
读多写少 Cache-Aside 最终一致 无影响
高并发写入 双删+消息队列 最终一致+ 中等
金融/交易场景 分布式锁+版本号 强一致

选择方案时,记得问自己一句你的业务真的需要强一致性吗?

相关文章
|
11月前
|
消息中间件 canal 缓存
缓存与数据库一致性终极指南:从入门到放弃?不,到精通!上
凌晨被投诉惊醒?缓存与数据库不一致是常见难题。本文详解五大解决方案:旁路缓存、双删策略、消息队列补偿、Binlog监听与版本号控制,结合场景分析一致性、性能与复杂度的权衡,助你选型不踩坑。
|
8月前
|
存储 数据管理 BI
什么是元数据?企业该如何进行元数据管理?
在数据驱动时代,元数据是描述数据的“数据”,涵盖业务、技术和管理信息。它能解决指标口径混乱、数据可信度低、变更影响难追溯等问题,是实现数据资产化、提升协作效率与合规水平的关键基础。
|
11月前
|
人工智能 Java API
Java AI智能体实战:使用LangChain4j构建能使用工具的AI助手
随着AI技术的发展,AI智能体(Agent)能够通过使用工具来执行复杂任务,从而大幅扩展其能力边界。本文介绍如何在Java中使用LangChain4j框架构建一个能够使用外部工具的AI智能体。我们将通过一个具体示例——一个能获取天气信息和执行数学计算的AI助手,详细讲解如何定义工具、创建智能体并处理执行流程。本文包含完整的代码示例和架构说明,帮助Java开发者快速上手AI智能体的开发。
3553 8
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
11月前
|
JSON 缓存 测试技术
程序出错瞎找?教你写“会说话”的错误日志,秒定位原因
错误日志是排查问题的“导航地图”。本文详解错误三大来源:参数非法、交互故障、逻辑疏漏,并分享写好日志的6大原则——完整、具体、直接、集成经验、格式统一、突出关键字,助你快速定位问题,提升系统可维护性。
675 0
|
10月前
|
SQL 监控 关系型数据库
mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)
本文总结MySQL索引失效的八大常见场景,如函数操作、类型不匹配、OR连接、违背最左前缀等,并结合实际案例解析。通过EXPLAIN分析执行计划,帮助开发者识别问题,提供优化策略,提升查询性能。
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
运维 NoSQL 算法
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
本文深入探讨了基于Redis实现分布式锁时遇到的细节问题及解决方案。首先,针对锁续期问题,提出了通过独立服务、获取锁进程自己续期和异步线程三种方式,并详细介绍了如何利用Lua脚本和守护线程实现自动续期。接着,解决了锁阻塞问题,引入了带超时时间的`tryLock`机制,确保在高并发场景下不会无限等待锁。最后,作为知识扩展,讲解了RedLock算法原理及其在实际业务中的局限性。文章强调,在并发量不高的场景中手写分布式锁可行,但推荐使用更成熟的Redisson框架来实现分布式锁,以保证系统的稳定性和可靠性。
1257 0
【📕分布式锁通关指南 04】redis分布式锁的细节问题以及RedLock算法原理
|
负载均衡 监控 Dubbo
Dubbo 原理和机制详解(非常全面)
本文详细解析了 Dubbo 的核心功能、组件、架构设计及调用流程,涵盖远程方法调用、智能容错、负载均衡、服务注册与发现等内容。欢迎留言交流。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Dubbo 原理和机制详解(非常全面)

热门文章

最新文章