缓存与数据库一致性?
作者:程序员马丁
note
热门项目实战社群,收获国内众多知名公司面试青睐,近千名同学面试成功!助力你在校招或社招上拿个offer。
答题思路
回答话术
缓存与数据库一致性是指在使用缓存的情况下,保证缓存中的数据与数据库中的数据保持一致的问题。
先写缓存再写数据库、先写数据库再写缓存、先删除缓存再写数据库这三种在实际工作中不建议使用,存在比较大的数据不一致隐患。
可以根据业务场景选择下述缓存一致性方案:
- 缓存双删:如果公司现有消息队列中间件,可以考虑使用该方案,反之则不需要考虑。
- 先写数据库再删缓存:这种方案从实时性以及技术实现复杂度来说都比较不错,推荐大家使用这种方案。
- Binlog 异步更新缓存:如果希望实现最终一致性以及数据多中心模式,该方案无疑是最合适的。
缓存与数据库一致性相关的几篇文章,我会以 12306 铁路购票系统 中购票扣减余量进行举例。
问题详解
1. 先写缓存再写数据库
两个用户购买了车站余票,假设余票有 17 张,两个用户扣减完还剩 15 张票。
如图所示,多个请求并发写入缓存和数据库,写请求 A 先更新 Redis 余票为 16。此时,写请求 B 将余票缓存更新 Redis 为 15,紧接着执行数据库更新为 15。这个时候,写请求 A 继续执行更新数据库操作,余票数据更新为 16。
这样就导致了多请求并发场景下,执行结果和咱们预期的结果不相符。
2. 先写数据库再写缓存
同上所诉,参考对应的业务场景和多请求并发场景,不同的是前者先更新缓存,后者先更新的是数据库,相同的是都存在并发问题,导致结果与预期并不相符。
3. 先删除缓存再写数据库
假设有两个并发的读写操作,一个是写操作,另一个是读操作。
- 并发读写的情况下,写操作首先删除缓存,接下来需要执行更新数据库操作。
- 读操作发生,由于缓存已经被删除,读操作不得不从数据库中读取数据。然而,由于写操作尚未完成,数据库中的数据仍然是过时的。
- 写操作这时需要更新数据库中的值,更新后 MySQL 数据库是最新的值。
- 读操作将从数据库中查询到的过时数据再回写到缓存。
在这种情况下,读操作获取到的是过时的数据,尽管写操作已经完成。因为缓存被删除,读操作不得不从数据库中读取旧值,而不是最新的值。