You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
一致性问题多发生在数据更新阶段,目前有2种:
|
|
|
|
|
**(1) 先删除缓存,再更新数据库**
|
|
|
|
|
**(2) 先更新数据库,再删除缓存**
|
|
|
|
|
|
|
|
|
|
# 一、为什么不能更新缓存而要删除
|
|
|
|
|
因为并发情况下的执行顺序与预期不一致,会出现旧值覆盖新值的情况,如图所示
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19.png]]
|
|
|
|
|
线程1 先发起的更新请求,过了一段时间线程2也发起更新,但是由于线程2比线程1先执行完,当线程1执行完成后会覆盖线程2更新的缓存值,就导致了库与缓存数据不一致问题。因此并发环境下不要更新缓存。
|
|
|
|
|
|
|
|
|
|
# 二、为什么不能先删除缓存,再更新数据库
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19 1.png]]
|
|
|
|
|
如图所示,读请求如果没有命中缓存,会先查库再更新缓存。假如先删除缓存,再更新库,如下图所示:
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19 2.png]]
|
|
|
|
|
当写、读两个线程同时执行,由于读先执行完,读线程将缓存的val更新为a1,但是库中实际值是a2,此时出现不一致情况。
|
|
|
|
|
|
|
|
|
|
# 三、Cache-Aside Pattern
|
|
|
|
|
Cache-Aside Pattern,即旁路缓存模式,它的提出是为了尽可能地解决缓存与数据库的数据不一致问题。
|
|
|
|
|
通俗的说就是先更新库,再删除缓存,理想情况下会出现极短的不一致问题。
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19 3.png]]
|
|
|
|
|
如图所示,线程2 的查询在线程1之前完成,将缓存val设为a1,随后线程1删除缓存,当下一次查询时缓存没有命中,就会将缓存val设为a2,实现了一致性。
|
|
|
|
|
|
|
|
|
|
## 3.1 不一致场景
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19 4.png]]
|
|
|
|
|
当读线程比写线程执行慢的时候又会产生不一致情况,直到缓存过期或下一次更新。因此引入了延迟双删策略。只需要保证,删除动作在写动作之后完成就能保证一致性。
|
|
|
|
|
|
|
|
|
|
## 3.2 延迟双删
|
|
|
|
|
![[Snipaste_2023-03-01_17-52-19 6.png]]
|
|
|
|
|
引入了第二次删除,将要删除的Key交给定时任务或MQ,只要线程2的写缓存操作在设定的延时范围内执行完成,就能保证一致性。延迟时间需要更新业务来设置。
|
|
|
|
|
|
|
|
|
|
## 3.3 改进延迟双删
|
|
|
|
|
假如删除缓存的动作失败了,需要加入重试机制。
|