缓存与数据库一致性的核心方案

缓存与数据库一致性的核心方案

一、旁路缓存 (Cache Aside)

适用场景:读多写少的业务场景,是目前业务开发中最常用的缓存一致性方案。

1. 核心执行逻辑

读流程

优先查询缓存,若缓存未命中,再查询数据库,最后将数据库查询结果回写至缓存,供后续请求复用。

写流程

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

核心说明 :写操作优先选择删除缓存而非更新缓存。删除操作具备简单、幂等的特性,能够有效规避并发写场景下的数据一致性问题,避免缓存数据与数据库数据错乱。

2. 核心痛点及解决方案

痛点一:高并发读写一致性问题

受网络延迟、读写并发、数据库主从同步延迟、事务未提交等因素影响,会出现缓存数据被污染的问题,具体执行流程如下:

  1. 线程A执行数据更新操作,率先完成数据库数据更新;

  2. 线程A随即删除对应缓存数据;

  3. 此时线程B发起数据读取请求,缓存为空触发数据库查询逻辑;

  4. 因数据库主从同步延迟、线程A事务未完全提交等原因,线程B查询到数据库旧数据;

  5. 线程B将查询到的旧数据回写入缓存,最终形成数据库为新数据、缓存为旧数据的不一致状态,且该错误数据会一直留存,直至缓存过期。

常规优化方案 :延迟双删策略,延迟时间常规设置为 200ms~500ms,错开读写并发的时间窗口,避免旧数据回写缓存。

痛点二:缓存删除失败问题

若直接删除缓存失败,会导致缓存留存旧数据,引发数据不一致。可将缓存删除操作交由MQ处理,依托MQ的消息重试、持久化机制,保障缓存删除操作最终执行成功。

3. 终极解决方案:Canal 监听 Binlog

通过Canal组件监听MySQL的Binlog日志(读写分离架构下监听从库Binlog),异步感知数据库数据变更,自动执行缓存删除或更新操作。该方案对业务代码完全无侵入,可靠性极高,可同时解决上述两大痛点。

方案核心原理(MySQL 两阶段提交机制)
  1. Prepare阶段:InnoDB引擎将数据写入redo log日志,并将事务状态标记为prepare;

  2. Binlog写入阶段:记录数据逻辑变更信息,写入Binlog日志并刷盘持久化;

  3. Commit阶段:InnoDB将redo log事务状态更新为commit,完成事务提交。

MySQL宕机恢复机制:若事务在Commit阶段宕机,重启后MySQL会校验Binlog完整性。只要Binlog日志已完整写入,即便redo log处于prepare状态,MySQL也会判定事务有效并自动提交。因此,只要Canal读取到Binlog日志,即可判定数据库数据已提交生效,以此保障缓存更新的准确性。

方案优势

传统MQ手动更新方案需改造业务代码,针对Redis、ES、大数据平台等不同中间件单独发送消息,代码冗余且扩展性差。而Canal可作为统一数据分发中心,通过下游配置多组消费者,分别处理Redis缓存更新、ES索引更新、HBase数据同步等需求,大幅简化业务架构。

4. 实战落地

实际开发中,可基于RedisTemplate、Jedis等主流Redis客户端,二次封装通用的CacheService缓存工具类,统一处理缓存查询、删除、更新等操作。

二、读/写直通 (Read/Write Through)

核心特性 :保障缓存与数据库强一致性,适用于对数据准确性、一致性要求极高的核心业务场景。

1. Read Through(读直通)

由缓存服务统一接管数据查询逻辑。业务请求查询数据时,若缓存未命中,缓存服务主动同步查询数据库,将数据加载至缓存后,再返回结果给业务应用,应用无需直接操作数据库。

2. Write Through(写直通)

由缓存服务统一接管数据写入逻辑。业务应用仅需写入缓存,缓存服务会同步将数据更新至数据库,仅当数据库写入成功后,才向应用返回写入成功结果。

3. 核心痛点

所有读写操作均需同步联动数据库,链路耗时较长,接口响应延迟高,并发性能较差。

4. 技术实现

Ehcache缓存框架原生提供CacheLoader(读加载)、CacheWriter(写写入)接口,开发者完成配置后,调用cache.put()等缓存方法,框架会自动执行数据库CRUD操作,无需手动编写SQL。

三、异步写回 (Write Back / Write Behind)

核心特性:以数据一致性为代价,极致提升写入并发性能,适用于高并发、弱一致性业务场景。

1. 执行逻辑

业务应用写入数据时,仅更新缓存即可立即返回成功结果,无需等待数据库写入。缓存服务会异步、批量将缓存中的增量数据刷入数据库,大幅提升接口吞吐能力。

2. 解决问题

完美适配超高并发写入场景,避免大量高频写请求直接冲击MySQL,导致数据库压力过载、宕机。

3. 核心痛点

存在数据丢失风险。若缓存节点在数据异步落库前宕机,未同步至数据库的缓存更新数据会永久丢失,无法恢复。

4. 典型应用场景

  • 社交媒体统计数据:点赞数、阅读量、浏览量等场景,少量数据误差不影响用户体验,但并发量极高,无法直接落地数据库;

  • 操作系统磁盘缓存:系统write()文件写入调用,采用的就是Write Back机制,数据先写入内存Page Cache,再由内核线程异步刷入硬盘。

相关推荐
江晓鱼未暖33 分钟前
十七、Redis 核心原理与架构详解
大数据·数据库·数据仓库·redis·缓存·架构
总捣什么乱11 小时前
MySQL MySQL是怎么保证主备一致的?
android·mysql·adb
小罗水1 小时前
第13章 Redis 缓存、幂等锁与任务状态
数据库·redis·缓存
热心市民lcj1 小时前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
zx1154502 小时前
【热点 Key 探测与加长缓存 TTL 实战】
缓存
鹿鸣天涯3 小时前
应急响应:MySQL日志分析
mysql·安全·adb·oracle
学编程就要猛3 小时前
解析博客系统后端实现
java·mysql·jwt·摘要算法·加盐
toooooop816 小时前
如何用 ss + ps 精准定位本机 Redis 的“隐形”消费者?
linux·数据库·redis·缓存
软萌萌的116 小时前
C#中的多级缓存架构设计与实现深度解析
缓存·c#·wpf
96245619 小时前
从 DBeaver 内存溢出到流式导入:一个 MySQL 生产数据迁移工具的开发实战
数据库·mysql·adb