请先了解旁路模式和延迟双删的正常流程。再考虑不正常的情况。否则容易混。
-
Cache Aside Pattern(旁路缓存模式)
更新请求 :更新数据库 -> 删除缓存
读取请求 : 读取缓存 -> 读取mysql ->写入缓存
不正常的问题:
- 更新和删除 的倒序情况:
1. 读取请求倒序:不能倒序! 一定要 先 读取缓冲 的!不然加缓存有什么用!
2. 更新请求倒序:如果先删除缓存,再更新数据库的问题:
查询+更新 的异常情况:
线程A (更新操作) | 线程B(查询操作) |
删除缓存 (num = 1) | |
缓存查不到 | |
去数据库查询 (num = 1) | |
更新数据库(num = 2) | |
写入缓存(num = 1) |
更新+更新的异常情况
没什么问题!
- 先更新数据 再删除缓存一定没问题吗?
更新+查询
线程A(更新操作) | 线程B(查询操作) |
缓存查不到 | |
去mysql查(num = 1) | |
更新数据库(num=2) | |
删除缓存 | |
写入缓存(num=1) |
更新+更新
没什么问题!
那既然旁路模式 是有问题的,为什么 我们还要使用?
这个在实际当中发生的概率很小。为什么?
因为缓存的写入通常要远远快于数据库的写入,所以实际当中,很少会出现请求B将数据库更新并且删除缓存后,请求A才写回缓存的情况。
延迟双删
读策略:读取缓存 - > 未命中 读取mysql ->写入缓存
写策略:删除缓存 -> 更新数据库 - > 延时sleep -> 删除缓存
那么为什么要延迟一会呢?
如果不延迟的话:
线程A (更新操作) | 线程B(查询操作) |
删除缓存 (num = 1) | |
缓存查不到 | |
去数据库查询 (num = 1) | |
更新数据库(num = 2) | |
| |
删除缓存 | |
写入缓存(num = 1) |
对吧,另一个查询操作的写入缓存操作 会跑到 更新操作的删除之后!所以需要延时双删。
为什么要先删一次呢?
(这个我本人的理解,如有更合理的理解欢迎留言!😀🙏🙏)
线程A (更新操作) | 线程B(查询操作) |
| |
缓存查不到 | |
去数据库查询 (num = 1) | |
更新数据库(num = 2) | |
写入缓存(num = 1) | |
sleep | |
删除缓存 |
大部分的时候可以提前保证一致性。