缓存一致性解决方法

对于缓存 + 数据库读写,有个经典的Cache Aside Pattern:
读取:先读取缓存,缓存里没有,读取数据库,然后返回响应,顺便保存缓存:
在这里插入图片描述
更新:先更新数据库,然后删除缓存
在这里插入图片描述

为什么是删除缓存而不是更新缓存?

  • 并发情况下更新缓存可能会带来更多问题,直接删除缓存更加稳妥
  • 缓存更新消耗更多资源,直接删除,用时再从数据库读取,写进缓存,更省性能

先更新数据库,然后删除缓存

一致性问题

假设更新数据库成功,接下来还没来得及删除缓存,或者删除缓存失败,此时其他线程进来读的就是脏数据。
在这里插入图片描述
既然删除缓存失败会导致脏数据,那么就得想办法能让它删除成功。一般来说有两种方法:消息队列重试机制监听binlog异步删除
消息队列重试机制
如果删除缓存失败,向消息队列发送消息,把删除失败的key放进去,消费消息队列,获取要删除的key,然后重试删除。
在这里插入图片描述

这样做的话引入了消息队列,对现有的业务造成了入侵,复杂度升高

监听binlog异步删除
用一个服务去监听数据库的binlog,获取需要操作的数据。然后用另外一个服务获取订阅程序传来的信息,进行缓存删除操作。这样对于业务的入侵就小了。
在这里插入图片描述

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

在并发情况下,先删除缓存,再更新数据库,此时数据库还未更新成功,这时有其他线程进来,读取缓存,缓存不存在,读取数据库,读取的是就是旧值,此时缓存不一致就发生了
解决方案便是延时双删
就是在删除缓存,更新数据库之后,休眠一段时间后,再次删除缓存。延时删除之后,就把缓存里面缓存的旧值删除了。
再有请求进来,就是读取数据库里的新值,再把新值保存进缓存。如果第二次删除也失败,那么就再次重试。

图1 缓存不一致
图2 延时双删

Guess you like

Origin blog.csdn.net/qq_42604176/article/details/120657573