在分布式系统中,如何保证缓存与数据库的数据一致性?(持续更新中)

一键三连,让算法推荐更多类似干货 ~
你最近面试被问到的最难的题是什么? 评论区交流,我来解答。
突然发现自己欠了一屁股 技术债 ? 别薅头发了 —— 关注本专栏,带你清债~

口诀:

读多写少旁路,先更库再删缓存;
强一致写透,缓存代理更库走;
性能优先写回,异步批量有风险;
高并发双删,延迟兜底防旧残;
强一致锁串,并发虽低稳如山。

(点个赞,算法会给你推荐更多类似干货 ~)

一、核心方案及适用场景

1. Cache Aside Pattern(缓存旁路模式)

在这里插入图片描述

“旁路” 的意思是 “侧面辅助”。

流程:

读操作:先查缓存,命中则返回;未命中则查数据库,再将数据写入缓存。

写操作:先更新数据库,再删除缓存(而非更新缓存)。

为什么删缓存而非更新?

避免 “并发写” 导致的不一致:比如请求 1 更新数据库后正要更新缓存,请求 2 已修改数据库并更新了缓存,此时请求 1 的旧数据会覆盖新数据。删除缓存可让下次读请求重新从数据库加载最新数据。

适用场景:

读多写少(如商品详情页),对一致性要求不极致(允许短暂缓存缺失)。

2. Write Through(写透模式)

在这里插入图片描述
写透:写操作时,数据会 “穿透” 缓存直接到达数据库。

流程:

写操作时,先更新缓存,再由缓存同步更新数据库(缓存作为数据库的 “代理”)。

优点:

缓存与数据库强一致,写完缓存即保证数据库也更新。

缺点:

写操作延迟高(需等数据库确认),不适合高并发写场景。

适用场景:

对一致性要求高、写操作不频繁的场景(如金融账户余额)。

3. Write Back(写回模式)

在这里插入图片描述

流程:

写操作时只更新缓存,缓存异步批量更新数据库(如设置定时刷新)。

优点:

写操作性能极高(不阻塞数据库)。

缺点:

缓存故障会导致数据丢失,一致性最差。

适用场景:

对性能要求极高、可容忍短暂数据丢失的场景(如日志缓存)。

写入缓存失败 怎么办:

先自救(重试)→ 再兜底(降级)→ 最后根治(监控修复)
(一)重试机制
(二)同步写数据库(降级为写穿模式)
适合 “业务绝对不能丢数据” 的场景(如金融交易记录、订单关键信息)。
(三)临时落本地文件,后续定时任务重试。
适合 “数据很重要,但当前所有存储都故障” 的极端情况。
(四)监控与告警
通过监控系统(如 Prometheus)统计 “缓存写入失败次数”,超过阈值(如 1 分钟内失败 10 次)触发告警,通知运维抢修。
所有降级逻辑都是 “临时补丁”,核心是让问题暴露并被修复。

4. 延迟双删(解决缓存删除延迟问题)

在这里插入图片描述
在这里插入图片描述

流程:

写操作时,先更新数据库,再删缓存;
延迟一段时间(如 500ms),再次删除缓存。

作用:

避免 “读请求在写请求更新数据库前加载了旧缓存” 导致的不一致(第一次删缓存可能因网络延迟没生效,第二次删除兜底)。

适用场景:

高并发读写场景(如秒杀商品库存更新)。

5. 分布式锁 + 串行化(强一致性保障)

在这里插入图片描述

流程:

读写操作都加分布式锁,确保同一数据的读写串行执行(先完成写操作,再允许读操作加载新数据)。

优点:

彻底避免并发冲突,数据强一致。

缺点:性能低(串行化牺牲并发)。

适用场景:数据一致性要求极高(如交易金额),并发量不高的场景。

一键三连,让算法推荐更多类似干货 ~
你最近面试被问到的最难的题是什么? 评论区交流,我来解答。
突然发现自己欠了一屁股 技术债 ? 别薅头发了 —— 关注本专栏,带你清债~

如有需完善的地方,也请大家不吝赐教!感谢!
在这里插入图片描述

为了保证 Redis 缓存数据库之间的数据一致性,通常可以采用以下几种策略: ### 先更新数据库,再更新缓存 在这种策略中,先将数据写入数据库,然后从缓存中删除相应的键。当后续的请求再次访问该数据时,会从数据库中重新加载最新的数据到缓存中。这种方式可以确保缓存中的数据始终数据库保持一致,但可能会导致缓存穿透的问题。 ```python def update_data(key, new_data): # 更新数据库中的数据 db.update(key, new_data) # 删除缓存中的键 redis.delete(key) ``` ### 先删除缓存,再更新数据库 在这种策略中,首先删除缓存中的键,然后更新数据库中的数据。如果在删除缓存更新数据库失败,则缓存数据库中的数据仍然一致。然而,在高并发场景下,可能会出现数据不一致的情况。 ```python def update_data(key, new_data): # 删除缓存中的键 redis.delete(key) # 更新数据库中的数据 db.update(key, new_data) ``` ### 延时双删策略 延时双删策略是为了克服先删除缓存更新数据库可能导致的数据不一致问题。具体步骤是:删除缓存更新数据库、延时一段时间后再次删除缓存。这种方式可以确保在高并发场景下数据的一致性。 ```java public void write(String key, Object data) { Redis.delKey(key); db.updateData(data); Thread.sleep(1000); // 延时一段时间 Redis.delKey(key); } ``` ### 使用消息队列 可以使用消息队列来异步处理缓存数据库更新操作。当数据发生变化时,将更新操作放入消息队列中,由消费者线程异步更新缓存数据库。这种方式可以提高系统的吞吐量,但需要处理消息队列中的消息丢失和重复消费问题。 ### 使用分布式锁 在高并发场景下,可以使用分布式锁来确保同一时间只有一个线程可以更新缓存数据库。这种方式可以避免数据不一致的问题,但会增加系统的复杂性和性能开销。 ### 使用数据库触发器 可以通过数据库触发器来监听数据库的变化,并在变化时自动更新缓存。这种方式可以确保缓存数据库的一致性,但实现起来较为复杂,并且可能会影响数据库的性能。 选择合适的策略需要根据具体的业务场景和需求来决定。在实际应用中,可以结合多种策略来提高系统的性能和数据的一致性[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值