Redis 与数据库不一致的四类根因与写入策略
【摘要】 短期与长期不一致的区分、四类根因(删缓存失败/并发竞态/主从延迟/永不过期)及推荐写入策略。
Redis 缓存和数据库不一致,绝大多数不是缓存坏了,而是更新顺序或失败处理没做对。这篇把四类根因和对应解法讲清楚。
一、先搞清楚不一致的两种形态
第一种是短期不一致:写入后短暂时间窗口内读到旧值,几十毫秒到几秒后自愈。第二种是长期不一致:缓存里的值再也回不到正确状态,只能人工修数据。
短期不一致可以接受,长期不一致必须设计层面避免。
二、四类常见根因
1. 先更新数据库再删缓存,但删除失败
UPDATE users SET name = 'x' WHERE id = 1;
DELETE FROM cache WHERE key = 'user:1'; -- 这一步失败了
数据库已经是新值,缓存还是旧值,而且不会自愈——下次读缓存直接命中旧数据。正确做法是给缓存设过期时间作为兜底,并在删除失败时重试或投递到消息队列补偿。
2. 并发读写导致删缓存顺序错乱
经典的 Cache Aside 竞态:
线程A: 读缓存 miss → 读DB(v1) → 准备写缓存
线程B: 更新DB(v2) → 删除缓存
线程A: 写入缓存(v1) ← 旧值覆盖了已删除的缓存
结果是缓存里长期留着 v1。缓解手段:延迟双删(更新后删一次,几百毫秒后再删一次),或者用版本号让旧值写不进去。
3. 主从延迟放大窗口
删缓存的操作走主库,但之后的读请求可能落到从库,读到还没同步的旧数据,又写回缓存。窗口随着主从延迟变长而变大。
解法是让读己之写的请求强制走主库,或者用 binlog 订阅(Canal)异步失效缓存,把延迟控制在可控范围。
4. 缓存永不过期
很多团队为了命中率把 TTL 设成永久。一旦出现上面任何一种不一致,就再也回不来了。
经验值:业务热点数据 TTL 设 5 到 30 分钟,非热点设 1 小时以内。命中率损失很小,但给了系统兜底能力。
三、排查顺序
- 对比缓存和数据库同一 key 的值,确认是否真的不一致
- 看这个 key 的 TTL,是 -1(永不过期)就优先怀疑设计问题
- 查更新代码路径:是否删了缓存、是否吞了异常
- 看主从延迟指标,判断是否是延迟窗口导致
- 确认并发量,评估是否命中 Cache Aside 竞态
四、推荐的写入策略
综合下来,先更新数据库,再删除缓存,配合合理 TTL 和失败重试是性价比最高的方案。不要用「更新缓存」代替「删除缓存」——并发写缓存的竞态比删缓存更难排查。
如果业务对一致性要求极高,就该考虑绕过缓存直接读库,而不是在缓存层做复杂补偿。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)