Redis缓存同步怎么做才能保证数据一致性,步骤和注意点聊聊
- 问答
- 2026-01-03 06:37:10
- 2
下面我分几种常见的场景和步骤来说,并谈谈每一步需要注意的地方。
最常用的方法:缓存失效 + 延迟双删
这是最基础也最常用的一种策略,理解起来不复杂。
步骤:
- 先更新数据库: 当业务需要修改数据时(比如修改商品价格),第一步永远是先去把数据库里的数据成功更新掉,这是数据的源头,必须最先保证它是对的。
- 立刻删除缓存: 在数据库更新成功后,立刻把 Redis 中对应的缓存数据删除掉,这一步是关键,目的是为了让旧的、已经不对的数据从缓存中消失。
- 短暂延迟后,再次删除缓存(可选但推荐): 过一小段时间(比如几百毫秒或一秒),再次尝试删除一次同一个缓存 key,这一步被称为“延迟双删”。
为什么需要“延迟双删”? 这里有个经典的坑,假设在“先更新数据库,再删除缓存”这个过程中,发生了这样的情况:

- 请求A来更新数据库。
- 在A还没删除缓存的时候,请求B来读数据了,B发现缓存里有数据(旧数据),于是直接返回给了用户。
- A才把缓存删除。 这样一来,用户就读到了旧数据,虽然下次再读就会更新成新数据,但这一次的请求确实出错了。
“延迟双删”就是为了解决这个时间差问题,在第一次删除后,等待一小段时间,这个时间要大于请求B读缓存和写缓存可能花费的时间(主从数据库同步延迟也要考虑进去),然后再删一次,确保把可能在这个极短时间窗口内被请求B误写入的旧数据再次清理掉。
注意点:
- 删除缓存可能失败: 网络抖动或者 Redis 服务暂时不可用都可能导致删除缓存失败,删除操作最好有重试机制,如果删除失败,可以把删除任务扔到一个消息队列里,由后台任务不断重试,直到成功。
- 延迟时间的设定: 第二次删除的延迟时间需要根据实际业务评估,太短了可能覆盖不了时间窗口,太长了又会导致缓存空窗期过长,增加数据库压力,通常需要压测和经验值。
- 对一致性要求极高的场景: 这种方法理论上还是存在极短时间的不一致窗口,如果业务对一致性要求是100%强一致(比如金融扣款),这个方法就不太够用。
更复杂但更稳妥的方法:先删缓存,再更新数据库
这个顺序调换了一下,但也会带来新问题。
步骤:

- 先删除缓存: 在更新数据库之前,先把缓存删了。
- 再更新数据库: 然后再去更新数据库。
这个方法的坑和解决方案: 这个策略的主要问题是,在删除缓存后、数据库更新完成前,可能会发生:
- 请求A删除了缓存。
- 请求B来读数据,发现缓存没了,于是去数据库查(此时数据库还是旧数据),然后把查到的旧数据又写回了缓存。
- 请求A才更新完数据库。 结果就是,缓存里的是旧数据,数据库里的是新数据,缓存长时间处于“脏数据”状态。
为了解决这个问题,可以结合上面提到的 “延迟双删”:
- 在步骤2(更新数据库)之后,再执行一次延迟删除,这样就能把请求B误写入的旧数据给清理掉。
注意点:
- 这种方法的数据不一致窗口期可能比第一种方法更长,因为脏数据可能在缓存中存在的时间是从请求B读库到第二次删除之间的整个间隔。
- 同样需要处理删除失败的重试问题。
追求强一致的进阶方法:订阅数据库日志(Canal)
这是目前比较流行的一种能近乎实现强一致的方案,但对技术架构有要求。

步骤:
- 更新数据库: 业务代码就正常更新数据库(比如MySQL)。
- 数据库生成日志: MySQL 会把自己所有的数据变更记录在一个叫 binlog 的日志文件里。
- 日志订阅工具(如Canal)读取日志: 有一个中间件(比如阿里开源的Canal)会伪装成MySQL的从库,实时读取这个binlog日志。
- 工具解析日志并删除/更新缓存: Canal解析出日志里具体是哪些数据变了(比如哪张表、哪条数据、变成了什么),然后调用一个简单的程序去删除Redis中对应的缓存。
为什么这个方法好? 因为它把缓存更新的逻辑和业务代码完全解耦了,业务代码只关心把数据库写好,完全不用操心缓存的事,缓存同步由一个独立的、可靠的数据管道来保证。
注意点:
- 架构复杂: 需要引入并维护Canal等中间件,增加了系统的复杂度。
- 延迟: 虽然是实时,但依然有毫秒级的延迟,并非绝对的“。
- 顺序性: 必须保证缓存操作的顺序和数据库变更的顺序完全一致,否则还是会乱。
一些通用的重要注意点
无论用哪种方法,下面几点都值得注意:
- 缓存要不要设过期时间? 一定要设! 这是最后的兜底策略,即使你的同步策略在某些极端情况下失败了,设置了过期时间的缓存最多当一段时间“僵尸”,到期后自动消失,下次查询就会从数据库加载正确数据,这能有效防止脏数据永不过期的问题。
- 是删除缓存还是更新缓存? 在大多数情况下,删除(Delete)比更新(Update)好,因为更新缓存可能涉及复杂的逻辑计算,而且如果连续多次更新,顺序错乱会导致数据问题,直接删除更简单粗暴,让下一个读请求来触发缓存重建,虽然可能增加一次读库,但保证了简单和正确。
- 热点数据问题: 当某个热点数据的缓存失效时,如果瞬间有大量请求同时涌向数据库,可能会把数据库压垮,这就是“缓存击穿”,解决方法可以是使用互斥锁(Mutex Lock),只让一个请求去数据库加载数据,其他请求等待。
- 降级策略: 要考虑到如果Redis完全不可用了,你的系统能不能直接访问数据库提供服务?虽然慢一点,但总比全站瘫痪好,这就是容灾降级的思想。
没有一种方法是完美的。“缓存失效 + 延迟双删” 是平衡了复杂度和一致性的常用选择,如果追求更高一致性且技术实力允许,“订阅数据库日志” 是更好的方向,最关键的是,要根据自己业务的可接受不一致的时间窗口和技术团队的运维能力来选择最适合的方案,并做好失败重试和过期兜底。
本文由邝冷亦于2026-01-03发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/73547.html
