Redis(13)| 缓存与数据库数据一致性问题

本文讨论的前提:

  1. 不是一个事务,永远无法满足数据库和缓存的强一直性的;
  2. 文中会列举不一致的逻辑场景;
  3. 一定是依解决业务问题,和业务达成的共同目标为前提;

前言

只要用到多数据源存储同一份相同的数据,在更新时,都会考虑数据一致性问题。这是常见问题,但是对于分布式系统的CAP 理论,相信很多人都听过,它是指:一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

为什么要理解 CAP 理论?

我能说出很多理由来。如果是在职场上,也许最合适的理由是,当领导给出的任务不靠谱时,我们可以依据 CAP 去否决它。比如,有这么一个任务,给你定了个大目标:

1. 这个系统满足编辑后数据要有实时性可见;
2. 还要系统的可用性,即响应效率高、响应结果合理,不能有bug;
3. 分区容错能力要高故障率99.9999%;

这个目标能完成吗?

本次讨论的数据库和缓存的数据一致性,就是Consistency。

为什么出现数据不一致

我们引入缓存机制,目的是:提高查询效率,这是初衷和前提,在并发场景下,也引入了一个问题,**何时去更新缓存?**在数据更新时,不仅要更新数据库,而且要更新缓存等,有如下集中情况

1.先更新数据库,再更新缓存

举个例子,比如「请求 A 」和「请求 B 」两个请求,同时更新「同一条」数据,则可能出现这样的顺序:

A 请求先将数据库的数据更新为 1,然后在更新缓存前,请求 B 将数据库的数据更新为 2,紧接着也把缓存更新为 2,然后 A 请求更新缓存为 1。

此时,数据库中的数据是 2,而缓存中的数据却是 1,出现了缓存和数据库中的数据不一致的现象。

2. 先更新缓存,再更新数据库

那换成「先更新缓存,再更新数据库」这个方案,还会有问题吗?

依然还是存在并发的问题,分析思路也是一样。

假设「请求 A 」和「请求 B 」两个请求,同时更新「同一条」数据,则可能出现这样的顺序:

A 请求先将缓存的数据更新为 1,然后在更新数据库前,B 请求来了, 将缓存的数据更新为 2,紧接着把数据库更新为 2,然后 A 请求将数据库的数据更新为 1。

此时,数据库中的数据是 1,而缓存中的数据却是 2,出现了缓存和数据库中的数据不一致的现象。

所以,无论是「先更新数据库,再更新缓存」,还是「先更新缓存,再更新数据库」,这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象。

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

假设某个用户的年龄是 20,请求 A 要更新用户年龄为 21,所以它会删除缓存中的内容。这时,另一个请求 B 要读取这个用户的年龄,它查询缓存发现未命中后,会从数据库中读取到年龄为 20,并且写入到缓存中,然后请求 A 继续更改数据库,将用户的年龄更新为 21。

最终,该用户年龄在缓存中是 20(旧值),在数据库中是 21(新值),缓存和数据库的数据不一致。

可以看到,先删除缓存,再更新数据库,在「读 + 写」并发的时候,还是会出现缓存和数据库的数据不一致的问题。

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

继续用「读 + 写」请求的并发的场景来分析。

假如某个用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存中。

最终,该用户年龄在缓存中是 20(旧值),在数据库中是 21(新值),缓存和数据库数据不一致。从上面的理论上分析,先更新数据库,再删除缓存也是会出现数据不一致性的问题,

解决方案

一切的技术方案都要根据业务合理的需求来。引入缓存是为了提高查询效率。

  1. 实时性不高的。比如:商详页、评价列表、点赞数等可以使用缓存过期时间+MQ/canal异步删除
  2. 实时性高的。比如商品库存、优惠券数量、保存在redis。并采用redisson提供的读写锁保证数据同步。
相关推荐
wind_one117 分钟前
7.基础--SQL--DDL-数据类型及案例
数据库·sql
爱敲键盘的猴子1 小时前
Redis内存回收,缓存问题
redis
l1t1 小时前
利用DeepSeek改写SQLite版本的二进制位数独求解SQL
数据库·人工智能·sql·sqlite
爬山算法1 小时前
Redis(110)Redis的发布订阅机制如何使用?
前端·redis·bootstrap
QT 小鲜肉1 小时前
【QT/C++】Qt定时器QTimer类的实现方法详解(超详细)
开发语言·数据库·c++·笔记·qt·学习
研究司马懿1 小时前
【ETCD】ETCD常用命令
网络·数据库·云原生·oracle·自动化·运维开发·etcd
刘一说3 小时前
深入理解 Spring Boot 中的数据库迁移:Flyway 与 Liquibase 实战指南
数据库·spring boot·oracle
August_._3 小时前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle
蓝象_3 小时前
docker下载配置redis
redis·docker·容器
升鲜宝供应链及收银系统源代码服务4 小时前
升鲜宝生鲜配送供应链管理系统---PMS--商品品牌多语言存储与 Redis 缓存同步实现
java·开发语言·数据库·redis·缓存·开源·供应链系统